repowisestage 0.0.40 → 0.0.41

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 +1154 -544
  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 dirname5, 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 dirname17, 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 dirname12 } 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";
@@ -3016,25 +3022,193 @@ var LspClient = class extends EventEmitter {
3016
3022
  this.emit("notification", msg["method"], msg["params"]);
3017
3023
  return;
3018
3024
  }
3019
- if (msg["method"] !== void 0 && msg["id"] !== void 0) {
3020
- const method = msg["method"];
3021
- const reqId = msg["id"];
3022
- if (this.listenerCount("request") === 0) {
3023
- this.respondError(reqId, -32601, `method not found: ${method}`);
3025
+ if (msg["method"] !== void 0 && msg["id"] !== void 0) {
3026
+ const method = msg["method"];
3027
+ const reqId = msg["id"];
3028
+ if (this.listenerCount("request") === 0) {
3029
+ this.respondError(reqId, -32601, `method not found: ${method}`);
3030
+ return;
3031
+ }
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 } 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
+ function runNpmInstall(cwd, pkg2) {
3087
+ return new Promise((resolve4, reject) => {
3088
+ const child = spawn3("npm", ["install", "--no-audit", "--no-fund", "--silent", pkg2], {
3089
+ cwd,
3090
+ stdio: ["ignore", "pipe", "pipe"],
3091
+ env: { ...process.env }
3092
+ });
3093
+ let stderr = "";
3094
+ child.stderr.on("data", (chunk) => {
3095
+ stderr += chunk.toString();
3096
+ });
3097
+ child.on("error", (err) => reject(err));
3098
+ child.on("close", (code) => {
3099
+ if (code === 0) {
3100
+ resolve4();
3101
+ } else {
3102
+ reject(new Error(`npm install ${pkg2} exited ${(code ?? -1).toString()}: ${sanitizeNpmStderr(stderr)}`));
3103
+ }
3104
+ });
3105
+ });
3106
+ }
3107
+ function sanitizeNpmStderr(raw) {
3108
+ const truncated = raw.split("\n").slice(0, 3).join(" ").trim();
3109
+ return truncated.replace(/(https?:\/\/)[^@\s/]*@/g, (_match, scheme) => `${scheme}<redacted>@`);
3110
+ }
3111
+ async function pathExists(p) {
3112
+ try {
3113
+ await fs.access(p);
3114
+ return true;
3115
+ } catch {
3116
+ return false;
3117
+ }
3118
+ }
3119
+ async function detectRepoLanguages(repoRoot) {
3120
+ const found = /* @__PURE__ */ new Set();
3121
+ let inspected = 0;
3122
+ const MAX_INSPECT = 200;
3123
+ async function inspect(dir) {
3124
+ if (inspected >= MAX_INSPECT)
3125
+ return;
3126
+ let entries;
3127
+ try {
3128
+ entries = await fs.readdir(dir);
3129
+ } catch {
3130
+ return;
3131
+ }
3132
+ for (const name of entries) {
3133
+ if (inspected >= MAX_INSPECT)
3024
3134
  return;
3135
+ if (name.startsWith("."))
3136
+ continue;
3137
+ if (name === "node_modules" || name === "dist" || name === "build")
3138
+ continue;
3139
+ const lang = detectLanguage(name);
3140
+ if (lang) {
3141
+ found.add(lang);
3142
+ inspected += 1;
3025
3143
  }
3026
- this.emit("request", method, msg["params"], reqId);
3027
3144
  }
3028
3145
  }
3029
- failAllPending(err) {
3030
- for (const pending of this.pending.values()) {
3031
- if (pending.timer)
3032
- clearTimeout(pending.timer);
3033
- pending.reject(err);
3146
+ await inspect(repoRoot);
3147
+ let topEntries = [];
3148
+ try {
3149
+ topEntries = await fs.readdir(repoRoot);
3150
+ } catch {
3151
+ return found;
3152
+ }
3153
+ for (const name of topEntries) {
3154
+ if (name.startsWith("."))
3155
+ continue;
3156
+ if (name === "node_modules" || name === "dist" || name === "build")
3157
+ continue;
3158
+ const sub = join14(repoRoot, name);
3159
+ try {
3160
+ const stat7 = await fs.stat(sub);
3161
+ if (stat7.isDirectory())
3162
+ await inspect(sub);
3163
+ } catch {
3034
3164
  }
3035
- this.pending.clear();
3036
3165
  }
3037
- };
3166
+ return found;
3167
+ }
3168
+ async function prepareLspServersForRepos(repos) {
3169
+ const detected = /* @__PURE__ */ new Set();
3170
+ for (const r of repos) {
3171
+ if (!r.localPath)
3172
+ continue;
3173
+ try {
3174
+ const stat7 = await fs.stat(r.localPath);
3175
+ if (!stat7.isDirectory())
3176
+ continue;
3177
+ } catch {
3178
+ continue;
3179
+ }
3180
+ try {
3181
+ const langs = await detectRepoLanguages(r.localPath);
3182
+ for (const l of langs)
3183
+ detected.add(l);
3184
+ } catch {
3185
+ }
3186
+ }
3187
+ const results = [];
3188
+ for (const language of detected) {
3189
+ const configs = LSP_REGISTRY[language];
3190
+ const npmConfig = configs.find((c) => c.npmPackage);
3191
+ if (!npmConfig) {
3192
+ results.push({
3193
+ language,
3194
+ installed: false,
3195
+ alreadyPresent: false,
3196
+ skippedNoNpmPackage: true,
3197
+ hint: configs[0]?.installHint
3198
+ });
3199
+ continue;
3200
+ }
3201
+ const outcome = await ensureNpmLspInstalled(npmConfig);
3202
+ results.push({
3203
+ language,
3204
+ installed: outcome.installed,
3205
+ alreadyPresent: outcome.skipped === "already-present",
3206
+ skippedNoNpmPackage: false,
3207
+ error: outcome.error
3208
+ });
3209
+ }
3210
+ return results;
3211
+ }
3038
3212
 
3039
3213
  // ../listener/dist/lsp/workspace-session.js
3040
3214
  function keyOf(args) {
@@ -3050,10 +3224,14 @@ var WorkspaceManager = class {
3050
3224
  this.idleTimeoutMs = opts.idleTimeoutMs ?? 10 * 60 * 1e3;
3051
3225
  this.maxSessions = opts.maxSessions ?? 32;
3052
3226
  this.clientFactory = opts.clientFactory ?? ((config2, cwd) => {
3227
+ const env = { ...process.env };
3228
+ const lspBin = getLspBinDir();
3229
+ env.PATH = env.PATH ? `${env.PATH}:${lspBin}` : lspBin;
3053
3230
  const client = new LspClient({
3054
3231
  command: config2.command,
3055
3232
  args: config2.args,
3056
- cwd
3233
+ cwd,
3234
+ env
3057
3235
  });
3058
3236
  client.on("stderr", (line) => {
3059
3237
  process.stderr.write(`[lsp:${config2.id}] ${line}`);
@@ -3381,7 +3559,7 @@ var PathEscapeError = class extends Error {
3381
3559
  // ../listener/dist/mcp/graph-cache.js
3382
3560
  init_config_dir();
3383
3561
  import { readFile as readFile8, stat as stat3 } from "fs/promises";
3384
- import { join as join15 } from "path";
3562
+ import { join as join16 } from "path";
3385
3563
  var EVICT_DEBOUNCE_MS = 6e4;
3386
3564
  function assertSafeRepoId(repoId) {
3387
3565
  if (!repoId || typeof repoId !== "string") {
@@ -3396,7 +3574,7 @@ function assertSafeRepoId(repoId) {
3396
3574
  }
3397
3575
  function createGraphCache(options = {}) {
3398
3576
  const evictMs = options.evictDebounceMs ?? EVICT_DEBOUNCE_MS;
3399
- const resolvePath = options.resolveGraphPath ?? ((repoId) => join15(defaultRepoWiseHome(), "graphs", `${repoId}.json`));
3577
+ const resolvePath = options.resolveGraphPath ?? ((repoId) => join16(defaultRepoWiseHome(), "graphs", `${repoId}.json`));
3400
3578
  const entries = /* @__PURE__ */ new Map();
3401
3579
  const inFlight = /* @__PURE__ */ new Map();
3402
3580
  async function loadFromDisk(repoId) {
@@ -3905,7 +4083,7 @@ async function isLocallyConsented(flagPath2) {
3905
4083
  init_config_dir();
3906
4084
  import { createServer } from "http";
3907
4085
  import { mkdir as mkdir13, writeFile as writeFile13 } from "fs/promises";
3908
- import { dirname as dirname10, join as join16 } from "path";
4086
+ import { dirname as dirname10, join as join17 } from "path";
3909
4087
  import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
3910
4088
 
3911
4089
  // ../listener/dist/mcp/sanitize.js
@@ -5258,7 +5436,7 @@ function extractBearer(header) {
5258
5436
  return m ? m[1] : null;
5259
5437
  }
5260
5438
  function defaultEndpointFile() {
5261
- return join16(getConfigDir(), "listener.endpoint");
5439
+ return join17(getConfigDir(), "listener.endpoint");
5262
5440
  }
5263
5441
 
5264
5442
  // ../listener/dist/mcp/bootstrap.js
@@ -5266,7 +5444,7 @@ async function startMcp(options) {
5266
5444
  const disabled = process.env.REPOWISE_MCP_DISABLED === "true";
5267
5445
  const graphsDir = options.graphsDir ?? defaultGraphsDir();
5268
5446
  const graphCache = createGraphCache({
5269
- resolveGraphPath: (repoId) => join17(graphsDir, `${repoId}.json`)
5447
+ resolveGraphPath: (repoId) => join18(graphsDir, `${repoId}.json`)
5270
5448
  });
5271
5449
  if (disabled) {
5272
5450
  return {
@@ -5289,11 +5467,11 @@ async function startMcp(options) {
5289
5467
  }
5290
5468
  const firstRepoLocal = options.repos.find((r) => r.localPath)?.localPath;
5291
5469
  const mcpHome = defaultMcpHome();
5292
- const logFilePath = join17(mcpHome, "mcp-log.jsonl.enc");
5293
- const keyStore = createFileKeyStore(join17(mcpHome, "mcp-log.key"));
5470
+ const logFilePath = join18(mcpHome, "mcp-log.jsonl.enc");
5471
+ const keyStore = createFileKeyStore(join18(mcpHome, "mcp-log.key"));
5294
5472
  const mcpLogger = createMcpLogger({ filePath: logFilePath, keyStore });
5295
- const flagFilePath = join17(mcpHome, "mcp-log.flag");
5296
- const watermarkFilePath = join17(mcpHome, "mcp-log.watermark");
5473
+ const flagFilePath = join18(mcpHome, "mcp-log.flag");
5474
+ const watermarkFilePath = join18(mcpHome, "mcp-log.watermark");
5297
5475
  let uploader = null;
5298
5476
  let lastConsentState = false;
5299
5477
  function ensureUploader() {
@@ -5337,7 +5515,7 @@ async function startMcp(options) {
5337
5515
  apiBaseUrl: repo.apiUrl,
5338
5516
  getAuthToken: options.getAuthToken,
5339
5517
  repoId: repo.repoId,
5340
- targetPath: join17(graphsDir, `${repo.repoId}.json`),
5518
+ targetPath: join18(graphsDir, `${repo.repoId}.json`),
5341
5519
  graphCache,
5342
5520
  ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
5343
5521
  }));
@@ -5413,7 +5591,7 @@ async function startMcp(options) {
5413
5591
  apiBaseUrl: repo.apiUrl,
5414
5592
  getAuthToken: options.getAuthToken,
5415
5593
  repoId: repo.repoId,
5416
- targetPath: join17(graphsDir, `${repo.repoId}.json`),
5594
+ targetPath: join18(graphsDir, `${repo.repoId}.json`),
5417
5595
  graphCache,
5418
5596
  ...options.fetchImpl ? { fetchImpl: options.fetchImpl } : {}
5419
5597
  }));
@@ -5434,12 +5612,389 @@ async function startMcp(options) {
5434
5612
  };
5435
5613
  }
5436
5614
  function defaultGraphsDir() {
5437
- return join17(getConfigDir(), "graphs");
5615
+ return join18(getConfigDir(), "graphs");
5438
5616
  }
5439
5617
  function defaultMcpHome() {
5440
5618
  return getConfigDir();
5441
5619
  }
5442
5620
 
5621
+ // ../listener/dist/mcp/auto-config/index.js
5622
+ import { homedir as homedir4 } from "os";
5623
+
5624
+ // ../listener/dist/mcp/auto-config/writers/claude-code.js
5625
+ import { promises as fs3 } from "fs";
5626
+ import { join as join19 } from "path";
5627
+
5628
+ // ../listener/dist/mcp/auto-config/markers.js
5629
+ import { promises as fs2 } from "fs";
5630
+ import { dirname as dirname11 } from "path";
5631
+ async function writeMergedConfig(params) {
5632
+ const current = await readConfig(params.path);
5633
+ const servers = { ...current.mcpServers ?? {} };
5634
+ servers[params.serverName] = params.spec;
5635
+ const next = { ...current, mcpServers: servers };
5636
+ const canonical = canonicalize(next);
5637
+ const existing = safeExistingContent(params.path, current);
5638
+ if (existing === canonical)
5639
+ return "unchanged";
5640
+ await fs2.mkdir(dirname11(params.path), { recursive: true });
5641
+ await fs2.writeFile(params.path, canonical, "utf-8");
5642
+ return "written";
5643
+ }
5644
+ async function removeFromConfig(path, serverName) {
5645
+ const current = await readConfig(path);
5646
+ if (!current.mcpServers || !(serverName in current.mcpServers))
5647
+ return;
5648
+ const servers = { ...current.mcpServers };
5649
+ delete servers[serverName];
5650
+ const next = { ...current, mcpServers: servers };
5651
+ if (Object.keys(servers).length === 0) {
5652
+ delete next.mcpServers;
5653
+ }
5654
+ await fs2.writeFile(path, canonicalize(next), "utf-8");
5655
+ }
5656
+ async function readConfig(path) {
5657
+ try {
5658
+ const raw = await fs2.readFile(path, "utf-8");
5659
+ return JSON.parse(raw);
5660
+ } catch (err) {
5661
+ if (err.code === "ENOENT")
5662
+ return {};
5663
+ throw err;
5664
+ }
5665
+ }
5666
+ function canonicalize(config2) {
5667
+ const serversSorted = {};
5668
+ if (config2.mcpServers) {
5669
+ const keys = Object.keys(config2.mcpServers).sort();
5670
+ for (const k of keys)
5671
+ serversSorted[k] = normalizeSpec(config2.mcpServers[k]);
5672
+ }
5673
+ const top = {};
5674
+ const otherKeys = Object.keys(config2).filter((k) => k !== "mcpServers").sort();
5675
+ for (const k of otherKeys)
5676
+ top[k] = config2[k];
5677
+ if (Object.keys(serversSorted).length > 0)
5678
+ top.mcpServers = serversSorted;
5679
+ return JSON.stringify(top, null, 2) + "\n";
5680
+ }
5681
+ function normalizeSpec(spec) {
5682
+ const out = { command: spec.command };
5683
+ if (spec.args && spec.args.length > 0)
5684
+ out.args = [...spec.args];
5685
+ if (spec.env && Object.keys(spec.env).length > 0) {
5686
+ const sorted = {};
5687
+ for (const k of Object.keys(spec.env).sort())
5688
+ sorted[k] = spec.env[k];
5689
+ out.env = sorted;
5690
+ }
5691
+ return out;
5692
+ }
5693
+ function safeExistingContent(path, current) {
5694
+ try {
5695
+ return canonicalize(current);
5696
+ } catch {
5697
+ return null;
5698
+ }
5699
+ void path;
5700
+ }
5701
+
5702
+ // ../listener/dist/mcp/auto-config/writers/claude-code.js
5703
+ var claudeCodeWriter = {
5704
+ tool: "claude-code",
5705
+ async detect(repoRoot, home) {
5706
+ return await fileExists2(join19(repoRoot, "CLAUDE.md")) || await hasClaudeBinary(home);
5707
+ },
5708
+ async write(ctx) {
5709
+ const path = join19(ctx.repoRoot, ".mcp.json");
5710
+ const status2 = await writeMergedConfig({
5711
+ path,
5712
+ serverName: `repowise-${ctx.repoId}`,
5713
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5714
+ });
5715
+ return { status: status2, path };
5716
+ },
5717
+ async remove(ctx) {
5718
+ await removeFromConfig(join19(ctx.repoRoot, ".mcp.json"), `repowise-${ctx.repoId}`);
5719
+ }
5720
+ };
5721
+ async function fileExists2(path) {
5722
+ try {
5723
+ await fs3.access(path);
5724
+ return true;
5725
+ } catch {
5726
+ return false;
5727
+ }
5728
+ }
5729
+ async function hasClaudeBinary(home) {
5730
+ return fileExists2(join19(home, ".claude", "claude.json"));
5731
+ }
5732
+
5733
+ // ../listener/dist/mcp/auto-config/writers/cline.js
5734
+ import { promises as fs4 } from "fs";
5735
+ import { join as join20 } from "path";
5736
+ var clineWriter = {
5737
+ tool: "cline",
5738
+ async detect(repoRoot, home) {
5739
+ return await fileExists3(join20(repoRoot, ".clinerules")) || await fileExists3(join20(home, ".cline"));
5740
+ },
5741
+ async write(ctx) {
5742
+ const path = join20(ctx.home, ".cline", "mcp.json");
5743
+ const status2 = await writeMergedConfig({
5744
+ path,
5745
+ serverName: `repowise-${ctx.repoId}`,
5746
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5747
+ });
5748
+ return { status: status2, path };
5749
+ },
5750
+ async remove(ctx) {
5751
+ await removeFromConfig(join20(ctx.home, ".cline", "mcp.json"), `repowise-${ctx.repoId}`);
5752
+ }
5753
+ };
5754
+ async function fileExists3(path) {
5755
+ try {
5756
+ await fs4.access(path);
5757
+ return true;
5758
+ } catch {
5759
+ return false;
5760
+ }
5761
+ }
5762
+
5763
+ // ../listener/dist/mcp/auto-config/writers/codex.js
5764
+ import { promises as fs5 } from "fs";
5765
+ import { join as join21 } from "path";
5766
+ var codexWriter = {
5767
+ tool: "codex",
5768
+ async detect(_repoRoot, home) {
5769
+ return fileExists4(join21(home, ".codex"));
5770
+ },
5771
+ async write(ctx) {
5772
+ const path = join21(ctx.home, ".codex", "mcp.json");
5773
+ const status2 = await writeMergedConfig({
5774
+ path,
5775
+ serverName: `repowise-${ctx.repoId}`,
5776
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5777
+ });
5778
+ return { status: status2, path };
5779
+ },
5780
+ async remove(ctx) {
5781
+ await removeFromConfig(join21(ctx.home, ".codex", "mcp.json"), `repowise-${ctx.repoId}`);
5782
+ }
5783
+ };
5784
+ async function fileExists4(path) {
5785
+ try {
5786
+ await fs5.access(path);
5787
+ return true;
5788
+ } catch {
5789
+ return false;
5790
+ }
5791
+ }
5792
+
5793
+ // ../listener/dist/mcp/auto-config/writers/copilot.js
5794
+ import { promises as fs6 } from "fs";
5795
+ import { join as join22 } from "path";
5796
+ var copilotWriter = {
5797
+ tool: "copilot",
5798
+ async detect(repoRoot) {
5799
+ return fileExists5(join22(repoRoot, ".vscode"));
5800
+ },
5801
+ async write(ctx) {
5802
+ const path = join22(ctx.repoRoot, ".vscode", "mcp.json");
5803
+ const status2 = await writeMergedConfig({
5804
+ path,
5805
+ serverName: `repowise-${ctx.repoId}`,
5806
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5807
+ });
5808
+ return { status: status2, path };
5809
+ },
5810
+ async remove(ctx) {
5811
+ await removeFromConfig(join22(ctx.repoRoot, ".vscode", "mcp.json"), `repowise-${ctx.repoId}`);
5812
+ }
5813
+ };
5814
+ async function fileExists5(path) {
5815
+ try {
5816
+ await fs6.access(path);
5817
+ return true;
5818
+ } catch {
5819
+ return false;
5820
+ }
5821
+ }
5822
+
5823
+ // ../listener/dist/mcp/auto-config/writers/cursor.js
5824
+ import { promises as fs7 } from "fs";
5825
+ import { join as join23 } from "path";
5826
+ var cursorWriter = {
5827
+ tool: "cursor",
5828
+ async detect(repoRoot) {
5829
+ return await fileExists6(join23(repoRoot, ".cursor")) || await fileExists6(join23(repoRoot, ".cursorrules"));
5830
+ },
5831
+ async write(ctx) {
5832
+ const path = join23(ctx.repoRoot, ".cursor", "mcp.json");
5833
+ const status2 = await writeMergedConfig({
5834
+ path,
5835
+ serverName: `repowise-${ctx.repoId}`,
5836
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5837
+ });
5838
+ return { status: status2, path };
5839
+ },
5840
+ async remove(ctx) {
5841
+ await removeFromConfig(join23(ctx.repoRoot, ".cursor", "mcp.json"), `repowise-${ctx.repoId}`);
5842
+ }
5843
+ };
5844
+ async function fileExists6(path) {
5845
+ try {
5846
+ await fs7.access(path);
5847
+ return true;
5848
+ } catch {
5849
+ return false;
5850
+ }
5851
+ }
5852
+
5853
+ // ../listener/dist/mcp/auto-config/writers/gemini-cli.js
5854
+ import { promises as fs8 } from "fs";
5855
+ import { join as join24 } from "path";
5856
+ var geminiCliWriter = {
5857
+ tool: "gemini-cli",
5858
+ async detect(_repoRoot, home) {
5859
+ return fileExists7(join24(home, ".gemini"));
5860
+ },
5861
+ async write(ctx) {
5862
+ const path = join24(ctx.home, ".gemini", "settings.json");
5863
+ const status2 = await writeMergedConfig({
5864
+ path,
5865
+ serverName: `repowise-${ctx.repoId}`,
5866
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5867
+ });
5868
+ return { status: status2, path };
5869
+ },
5870
+ async remove(ctx) {
5871
+ await removeFromConfig(join24(ctx.home, ".gemini", "settings.json"), `repowise-${ctx.repoId}`);
5872
+ }
5873
+ };
5874
+ async function fileExists7(path) {
5875
+ try {
5876
+ await fs8.access(path);
5877
+ return true;
5878
+ } catch {
5879
+ return false;
5880
+ }
5881
+ }
5882
+
5883
+ // ../listener/dist/mcp/auto-config/writers/roo.js
5884
+ import { promises as fs9 } from "fs";
5885
+ import { join as join25 } from "path";
5886
+ var rooWriter = {
5887
+ tool: "roo",
5888
+ async detect(repoRoot, home) {
5889
+ return await fileExists8(join25(repoRoot, ".roo")) || await fileExists8(join25(home, ".roo"));
5890
+ },
5891
+ async write(ctx) {
5892
+ const repoConfig = join25(ctx.repoRoot, ".roo", "mcp.json");
5893
+ const useRepoScope = await fileExists8(join25(ctx.repoRoot, ".roo"));
5894
+ const path = useRepoScope ? repoConfig : join25(ctx.home, ".roo", "mcp.json");
5895
+ const status2 = await writeMergedConfig({
5896
+ path,
5897
+ serverName: `repowise-${ctx.repoId}`,
5898
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5899
+ });
5900
+ return { status: status2, path };
5901
+ },
5902
+ async remove(ctx) {
5903
+ await removeFromConfig(join25(ctx.repoRoot, ".roo", "mcp.json"), `repowise-${ctx.repoId}`);
5904
+ await removeFromConfig(join25(ctx.home, ".roo", "mcp.json"), `repowise-${ctx.repoId}`);
5905
+ }
5906
+ };
5907
+ async function fileExists8(path) {
5908
+ try {
5909
+ await fs9.access(path);
5910
+ return true;
5911
+ } catch {
5912
+ return false;
5913
+ }
5914
+ }
5915
+
5916
+ // ../listener/dist/mcp/auto-config/writers/windsurf.js
5917
+ import { promises as fs10 } from "fs";
5918
+ import { join as join26 } from "path";
5919
+ var windsurfWriter = {
5920
+ tool: "windsurf",
5921
+ async detect(_repoRoot, home) {
5922
+ return fileExists9(join26(home, ".codeium", "windsurf"));
5923
+ },
5924
+ async write(ctx) {
5925
+ const path = join26(ctx.home, ".codeium", "windsurf", "mcp_config.json");
5926
+ const status2 = await writeMergedConfig({
5927
+ path,
5928
+ serverName: `repowise-${ctx.repoId}`,
5929
+ spec: { command: ctx.shimCmd, args: ["--repo-id", ctx.repoId] }
5930
+ });
5931
+ return { status: status2, path };
5932
+ },
5933
+ async remove(ctx) {
5934
+ await removeFromConfig(join26(ctx.home, ".codeium", "windsurf", "mcp_config.json"), `repowise-${ctx.repoId}`);
5935
+ }
5936
+ };
5937
+ async function fileExists9(path) {
5938
+ try {
5939
+ await fs10.access(path);
5940
+ return true;
5941
+ } catch {
5942
+ return false;
5943
+ }
5944
+ }
5945
+
5946
+ // ../listener/dist/mcp/auto-config/writers/index.js
5947
+ var WRITERS = [
5948
+ claudeCodeWriter,
5949
+ clineWriter,
5950
+ codexWriter,
5951
+ copilotWriter,
5952
+ cursorWriter,
5953
+ geminiCliWriter,
5954
+ rooWriter,
5955
+ windsurfWriter
5956
+ ];
5957
+
5958
+ // ../listener/dist/mcp/auto-config/index.js
5959
+ async function runAutoConfig(opts) {
5960
+ const home = opts.home ?? homedir4();
5961
+ const writers = opts.writers ?? WRITERS;
5962
+ const results = [];
5963
+ for (const writer of writers) {
5964
+ let detected;
5965
+ try {
5966
+ detected = await writer.detect(opts.repoRoot, home);
5967
+ } catch (err) {
5968
+ results.push({
5969
+ tool: writer.tool,
5970
+ detected: false,
5971
+ error: err instanceof Error ? err.message : String(err)
5972
+ });
5973
+ continue;
5974
+ }
5975
+ if (!detected) {
5976
+ results.push({ tool: writer.tool, detected: false });
5977
+ continue;
5978
+ }
5979
+ try {
5980
+ const outcome = await writer.write({
5981
+ repoRoot: opts.repoRoot,
5982
+ repoId: opts.repoId,
5983
+ shimCmd: opts.shimCmd,
5984
+ home
5985
+ });
5986
+ results.push({ tool: writer.tool, detected: true, outcome });
5987
+ } catch (err) {
5988
+ results.push({
5989
+ tool: writer.tool,
5990
+ detected: true,
5991
+ error: err instanceof Error ? err.message : String(err)
5992
+ });
5993
+ }
5994
+ }
5995
+ return results;
5996
+ }
5997
+
5443
5998
  // ../listener/dist/typed-resolution/resolver-loop.js
5444
5999
  init_src();
5445
6000
  init_registry();
@@ -5644,7 +6199,7 @@ var CRASH_LOOP_WINDOW_MS = 3e4;
5644
6199
  var CRASH_LOOP_THRESHOLD = 3;
5645
6200
  async function readRawToolConfig() {
5646
6201
  try {
5647
- const configPath = join18(getConfigDir(), "config.json");
6202
+ const configPath = join27(getConfigDir(), "config.json");
5648
6203
  const data = await readFile12(configPath, "utf-8");
5649
6204
  const raw = JSON.parse(data);
5650
6205
  return {
@@ -5705,11 +6260,11 @@ function resolveAuditRoots() {
5705
6260
  return override.split(":").map((s) => s.trim()).filter(Boolean);
5706
6261
  }
5707
6262
  const out = /* @__PURE__ */ new Set();
5708
- let dir = dirname11(process.execPath);
6263
+ let dir = dirname12(process.execPath);
5709
6264
  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);
6265
+ out.add(join27(dir, "node_modules"));
6266
+ out.add(join27(dir, "lib", "node_modules"));
6267
+ const parent = dirname12(dir);
5713
6268
  if (parent === dir)
5714
6269
  break;
5715
6270
  dir = parent;
@@ -5928,7 +6483,7 @@ async function checkStaleContext(repos, state, groups) {
5928
6483
  if (group?.offline.isOffline)
5929
6484
  continue;
5930
6485
  const { statSync: statSync2, readdirSync: readdirSync2 } = await import("fs");
5931
- const contextPath = join18(repo.localPath, "repowise-context");
6486
+ const contextPath = join27(repo.localPath, "repowise-context");
5932
6487
  let isMissingOrEmpty = false;
5933
6488
  try {
5934
6489
  const s = statSync2(contextPath);
@@ -5957,9 +6512,36 @@ async function checkStaleContext(repos, state, groups) {
5957
6512
  }
5958
6513
  return dirty;
5959
6514
  }
6515
+ async function reconcileMcpConfigs(repos, packageName) {
6516
+ const shimCmd = packageName;
6517
+ for (const repo of repos) {
6518
+ if (!repo.localPath)
6519
+ continue;
6520
+ try {
6521
+ const s = await fsStat(repo.localPath);
6522
+ if (!s.isDirectory())
6523
+ continue;
6524
+ } catch {
6525
+ continue;
6526
+ }
6527
+ try {
6528
+ const results = await runAutoConfig({
6529
+ repoRoot: repo.localPath,
6530
+ repoId: repo.repoId,
6531
+ shimCmd
6532
+ });
6533
+ const written = results.filter((r) => r.detected && r.outcome?.status === "written");
6534
+ if (written.length > 0) {
6535
+ console.log(`[mcp-config] Wrote ${written.length.toString()} config(s) for ${repo.repoId}: ${written.map((r) => `${r.tool}=${r.outcome.path}`).join(", ")}`);
6536
+ }
6537
+ } catch (err) {
6538
+ console.warn(`[mcp-config] Reconcile failed for ${repo.repoId}:`, err instanceof Error ? err.message : String(err));
6539
+ }
6540
+ }
6541
+ }
5960
6542
  async function reconcileAgentInstructions(repos) {
5961
6543
  for (const repo of repos) {
5962
- const path = join18(repo.localPath, "repowise-context", "project-overview.md");
6544
+ const path = join27(repo.localPath, "repowise-context", "project-overview.md");
5963
6545
  let content;
5964
6546
  try {
5965
6547
  content = await readFile12(path, "utf-8");
@@ -6021,7 +6603,7 @@ async function startListener() {
6021
6603
  }
6022
6604
  const configDir = getConfigDir();
6023
6605
  await mkdir14(configDir, { recursive: true });
6024
- const lockPath = join18(configDir, "listener.lock");
6606
+ const lockPath = join27(configDir, "listener.lock");
6025
6607
  await writeFile14(lockPath, "", { flag: "a" });
6026
6608
  let lockIsHeld = false;
6027
6609
  try {
@@ -6064,7 +6646,7 @@ async function startListener() {
6064
6646
  return;
6065
6647
  }
6066
6648
  if (config2.repos.length === 0 && !config2.autoDiscoverRepos) {
6067
- console.error(`No repos configured. Add repos to ${join18(configDir, "config.json")}`);
6649
+ console.error(`No repos configured. Add repos to ${join27(configDir, "config.json")}`);
6068
6650
  await releaseLockAndExit();
6069
6651
  process.exitCode = 1;
6070
6652
  return;
@@ -6131,8 +6713,8 @@ async function startListener() {
6131
6713
  const packageName = true ? "repowisestage" : "repowise";
6132
6714
  let currentVersion = "";
6133
6715
  try {
6134
- const selfDir = dirname11(fileURLToPath3(import.meta.url));
6135
- const pkgJsonPath = join18(selfDir, "..", "..", "package.json");
6716
+ const selfDir = dirname12(fileURLToPath3(import.meta.url));
6717
+ const pkgJsonPath = join27(selfDir, "..", "..", "package.json");
6136
6718
  const pkgJson = JSON.parse(await readFile12(pkgJsonPath, "utf-8"));
6137
6719
  currentVersion = pkgJson.version;
6138
6720
  } catch (err) {
@@ -6185,6 +6767,29 @@ async function startListener() {
6185
6767
  } catch (err) {
6186
6768
  console.warn("[reconcile] Initial agent instructions reconciliation failed:", err instanceof Error ? err.message : String(err));
6187
6769
  }
6770
+ void (async () => {
6771
+ try {
6772
+ await reconcileMcpConfigs(config2.repos, packageName);
6773
+ } catch (err) {
6774
+ console.warn("[mcp-config] Initial MCP config reconciliation failed:", err instanceof Error ? err.message : String(err));
6775
+ }
6776
+ })();
6777
+ void (async () => {
6778
+ try {
6779
+ const lspResults = await prepareLspServersForRepos(config2.repos);
6780
+ for (const r of lspResults) {
6781
+ if (r.installed) {
6782
+ console.log(`[lsp-install] Installed ${r.language} LSP server`);
6783
+ } else if (r.skippedNoNpmPackage && r.hint) {
6784
+ console.log(`[lsp-install] ${r.language} LSP not auto-installable. To enable: ${r.hint}`);
6785
+ } else if (r.error) {
6786
+ console.warn(`[lsp-install] ${r.language} install failed: ${r.error}`);
6787
+ }
6788
+ }
6789
+ } catch (err) {
6790
+ console.warn("[lsp-install] Pre-install scan failed:", err instanceof Error ? err.message : String(err));
6791
+ }
6792
+ })();
6188
6793
  const typedResolutionHooks = mcpRuntime?.lspWorkspaces ? buildTypedResolutionHooks({
6189
6794
  workspaces: mcpRuntime.lspWorkspaces,
6190
6795
  graphCache: mcpRuntime.graphCache,
@@ -6385,6 +6990,11 @@ async function startListener() {
6385
6990
  } catch (err) {
6386
6991
  console.warn("[reconcile] Agent instructions reconciliation failed:", err instanceof Error ? err.message : String(err));
6387
6992
  }
6993
+ try {
6994
+ await reconcileMcpConfigs(config2.repos, packageName);
6995
+ } catch (err) {
6996
+ console.warn("[mcp-config] Reconciliation failed:", err instanceof Error ? err.message : String(err));
6997
+ }
6388
6998
  }
6389
6999
  if (latestCliVersion && currentVersion && !config2.noAutoUpdate && (state.crashCount ?? 0) < CRASH_LOOP_THRESHOLD) {
6390
7000
  if (latestCliVersion !== state.lastUpdateTargetVersion) {
@@ -6448,12 +7058,12 @@ async function startListener() {
6448
7058
  } catch {
6449
7059
  }
6450
7060
  }
6451
- const credentialsPath = join18(getConfigDir(), "credentials.json");
7061
+ const credentialsPath = join27(getConfigDir(), "credentials.json");
6452
7062
  let credentialsChanged = false;
6453
7063
  let watcher = null;
6454
7064
  try {
6455
- const fs8 = await import("fs");
6456
- watcher = fs8.watch(credentialsPath, () => {
7065
+ const fs18 = await import("fs");
7066
+ watcher = fs18.watch(credentialsPath, () => {
6457
7067
  credentialsChanged = true;
6458
7068
  });
6459
7069
  } catch {
@@ -6493,8 +7103,8 @@ if (isDirectRun) {
6493
7103
  }
6494
7104
 
6495
7105
  // src/lib/env.ts
6496
- import { homedir as homedir4 } from "os";
6497
- import { join as join19 } from "path";
7106
+ import { homedir as homedir5 } from "os";
7107
+ import { join as join28 } from "path";
6498
7108
  var IS_STAGING2 = true ? true : false;
6499
7109
  var PRODUCTION = {
6500
7110
  apiUrl: "https://api.repowise.ai",
@@ -6514,7 +7124,7 @@ function getEnvConfig() {
6514
7124
  return IS_STAGING2 ? STAGING : PRODUCTION;
6515
7125
  }
6516
7126
  function getConfigDir2() {
6517
- return join19(homedir4(), IS_STAGING2 ? ".repowise-staging" : ".repowise");
7127
+ return join28(homedir5(), IS_STAGING2 ? ".repowise-staging" : ".repowise");
6518
7128
  }
6519
7129
  function getPackageName() {
6520
7130
  return true ? "repowisestage" : "repowise";
@@ -6525,11 +7135,11 @@ import chalk from "chalk";
6525
7135
 
6526
7136
  // src/lib/config.ts
6527
7137
  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";
7138
+ import { join as join29 } from "path";
6529
7139
  import lockfile4 from "proper-lockfile";
6530
7140
  async function getConfig() {
6531
7141
  try {
6532
- const data = await readFile13(join20(getConfigDir2(), "config.json"), "utf-8");
7142
+ const data = await readFile13(join29(getConfigDir2(), "config.json"), "utf-8");
6533
7143
  return JSON.parse(data);
6534
7144
  } catch {
6535
7145
  return {};
@@ -6537,7 +7147,7 @@ async function getConfig() {
6537
7147
  }
6538
7148
  async function saveConfig(config2) {
6539
7149
  const dir = getConfigDir2();
6540
- const path = join20(dir, "config.json");
7150
+ const path = join29(dir, "config.json");
6541
7151
  await mkdir15(dir, { recursive: true });
6542
7152
  const tmpPath = path + ".tmp";
6543
7153
  try {
@@ -6553,7 +7163,7 @@ async function saveConfig(config2) {
6553
7163
  }
6554
7164
  async function mergeAndSaveConfig(updates) {
6555
7165
  const dir = getConfigDir2();
6556
- const path = join20(dir, "config.json");
7166
+ const path = join29(dir, "config.json");
6557
7167
  await mkdir15(dir, { recursive: true });
6558
7168
  try {
6559
7169
  await writeFile15(path, "", { flag: "a" });
@@ -6624,7 +7234,7 @@ async function showWelcome(currentVersion) {
6624
7234
 
6625
7235
  // src/commands/create.ts
6626
7236
  import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
6627
- import { dirname as dirname12, join as join24 } from "path";
7237
+ import { dirname as dirname13, join as join33 } from "path";
6628
7238
  init_src();
6629
7239
  import chalk5 from "chalk";
6630
7240
  import ora from "ora";
@@ -6633,7 +7243,7 @@ import ora from "ora";
6633
7243
  import { createHash as createHash3, randomBytes as randomBytes3 } from "crypto";
6634
7244
  import { readFile as readFile14, writeFile as writeFile16, mkdir as mkdir16, chmod as chmod4, unlink as unlink10 } from "fs/promises";
6635
7245
  import http from "http";
6636
- import { join as join21 } from "path";
7246
+ import { join as join30 } from "path";
6637
7247
  var CLI_CALLBACK_PORT = 19876;
6638
7248
  var CALLBACK_TIMEOUT_MS = 12e4;
6639
7249
  function getCognitoConfigForStorage() {
@@ -6799,7 +7409,7 @@ async function refreshTokens2(refreshToken) {
6799
7409
  }
6800
7410
  async function getStoredCredentials2() {
6801
7411
  try {
6802
- const credPath = join21(getConfigDir2(), "credentials.json");
7412
+ const credPath = join30(getConfigDir2(), "credentials.json");
6803
7413
  const data = await readFile14(credPath, "utf-8");
6804
7414
  return JSON.parse(data);
6805
7415
  } catch (err) {
@@ -6811,14 +7421,14 @@ async function getStoredCredentials2() {
6811
7421
  }
6812
7422
  async function storeCredentials2(credentials) {
6813
7423
  const dir = getConfigDir2();
6814
- const credPath = join21(dir, "credentials.json");
7424
+ const credPath = join30(dir, "credentials.json");
6815
7425
  await mkdir16(dir, { recursive: true, mode: 448 });
6816
7426
  await writeFile16(credPath, JSON.stringify(credentials, null, 2));
6817
7427
  await chmod4(credPath, 384);
6818
7428
  }
6819
7429
  async function clearCredentials() {
6820
7430
  try {
6821
- await unlink10(join21(getConfigDir2(), "credentials.json"));
7431
+ await unlink10(join30(getConfigDir2(), "credentials.json"));
6822
7432
  } catch (err) {
6823
7433
  if (err.code !== "ENOENT") throw err;
6824
7434
  }
@@ -7025,10 +7635,10 @@ async function selectAiTools() {
7025
7635
 
7026
7636
  // src/lib/ai-tools.ts
7027
7637
  import { readFile as readFile15, writeFile as writeFile17, mkdir as mkdir17 } from "fs/promises";
7028
- import { join as join22 } from "path";
7638
+ import { join as join31 } from "path";
7029
7639
  var REPOWISE_HOOK_MARKER = "repowise-context";
7030
7640
  async function writeClaudeSubagentHook(repoRoot, contextFolder) {
7031
- const settingsPath = join22(repoRoot, ".claude", "settings.json");
7641
+ const settingsPath = join31(repoRoot, ".claude", "settings.json");
7032
7642
  let settings = {};
7033
7643
  try {
7034
7644
  const raw = await readFile15(settingsPath, "utf-8");
@@ -7063,15 +7673,15 @@ async function writeClaudeSubagentHook(repoRoot, contextFolder) {
7063
7673
  }
7064
7674
  hooks["SubagentStart"] = subagentStart;
7065
7675
  settings["hooks"] = hooks;
7066
- await mkdir17(join22(repoRoot, ".claude"), { recursive: true });
7676
+ await mkdir17(join31(repoRoot, ".claude"), { recursive: true });
7067
7677
  await writeFile17(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
7068
7678
  }
7069
7679
 
7070
7680
  // src/lib/gitignore.ts
7071
7681
  import { readFileSync as readFileSync2, writeFileSync, existsSync } from "fs";
7072
- import { join as join23 } from "path";
7682
+ import { join as join32 } from "path";
7073
7683
  function ensureGitignore(repoRoot, entry) {
7074
- const gitignorePath = join23(repoRoot, ".gitignore");
7684
+ const gitignorePath = join32(repoRoot, ".gitignore");
7075
7685
  if (existsSync(gitignorePath)) {
7076
7686
  const content = readFileSync2(gitignorePath, "utf-8");
7077
7687
  const lines = content.split("\n").map((l) => l.trim());
@@ -7861,7 +8471,7 @@ async function create() {
7861
8471
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
7862
8472
  const files = listResult.data?.files ?? listResult.files ?? [];
7863
8473
  if (files.length > 0) {
7864
- const contextDir = join24(repoRoot, DEFAULT_CONTEXT_FOLDER);
8474
+ const contextDir = join33(repoRoot, DEFAULT_CONTEXT_FOLDER);
7865
8475
  mkdirSync(contextDir, { recursive: true });
7866
8476
  let downloadedCount = 0;
7867
8477
  let failedCount = 0;
@@ -7875,8 +8485,8 @@ async function create() {
7875
8485
  const response = await fetch(presignedUrl);
7876
8486
  if (response.ok) {
7877
8487
  const content = await response.text();
7878
- const filePath = join24(contextDir, file.fileName);
7879
- mkdirSync(dirname12(filePath), { recursive: true });
8488
+ const filePath = join33(contextDir, file.fileName);
8489
+ mkdirSync(dirname13(filePath), { recursive: true });
7880
8490
  writeFileSync2(filePath, content, "utf-8");
7881
8491
  downloadedCount++;
7882
8492
  } else {
@@ -8017,7 +8627,7 @@ Files are stored on our servers (not in git). Retry when online.`
8017
8627
 
8018
8628
  // src/commands/member.ts
8019
8629
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
8020
- import { dirname as dirname13, join as join25, resolve, sep } from "path";
8630
+ import { dirname as dirname14, join as join34, resolve, sep } from "path";
8021
8631
  import chalk6 from "chalk";
8022
8632
  import ora2 from "ora";
8023
8633
  var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
@@ -8141,7 +8751,7 @@ async function member() {
8141
8751
  spinner.succeed(`Found ${chalk6.bold(files.length)} context files on server`);
8142
8752
  const { tools } = await selectAiTools();
8143
8753
  spinner.start("Downloading context files...");
8144
- const contextDir = join25(repoRoot, DEFAULT_CONTEXT_FOLDER2);
8754
+ const contextDir = join34(repoRoot, DEFAULT_CONTEXT_FOLDER2);
8145
8755
  mkdirSync2(contextDir, { recursive: true });
8146
8756
  let downloadedCount = 0;
8147
8757
  let failedCount = 0;
@@ -8162,7 +8772,7 @@ async function member() {
8162
8772
  const response = await fetch(presignedUrl);
8163
8773
  if (response.ok) {
8164
8774
  const content = await response.text();
8165
- mkdirSync2(dirname13(safePath), { recursive: true });
8775
+ mkdirSync2(dirname14(safePath), { recursive: true });
8166
8776
  writeFileSync3(safePath, content, "utf-8");
8167
8777
  downloadedCount++;
8168
8778
  } else {
@@ -8286,15 +8896,15 @@ import chalk7 from "chalk";
8286
8896
  import ora3 from "ora";
8287
8897
 
8288
8898
  // 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");
8899
+ import { promises as fs11 } from "fs";
8900
+ import { homedir as homedir6 } from "os";
8901
+ import { join as join35 } from "path";
8902
+ async function purgeForeignGraphs(validRepoIds, home = homedir6()) {
8903
+ const graphsDir = join35(home, ".repowise", "graphs");
8294
8904
  const result = { kept: [], removed: [] };
8295
8905
  let entries;
8296
8906
  try {
8297
- entries = await fs.readdir(graphsDir);
8907
+ entries = await fs11.readdir(graphsDir);
8298
8908
  } catch (err) {
8299
8909
  if (err.code === "ENOENT") return result;
8300
8910
  throw err;
@@ -8308,15 +8918,15 @@ async function purgeForeignGraphs(validRepoIds, home = homedir5()) {
8308
8918
  result.kept.push(entry);
8309
8919
  continue;
8310
8920
  }
8311
- const path = join26(graphsDir, entry);
8921
+ const path = join35(graphsDir, entry);
8312
8922
  try {
8313
- const stat7 = await fs.lstat(path);
8923
+ const stat7 = await fs11.lstat(path);
8314
8924
  if (stat7.isSymbolicLink()) {
8315
- await fs.unlink(path);
8925
+ await fs11.unlink(path);
8316
8926
  result.removed.push(entry);
8317
8927
  continue;
8318
8928
  }
8319
- await fs.rm(path, { recursive: true, force: true });
8929
+ await fs11.rm(path, { recursive: true, force: true });
8320
8930
  result.removed.push(entry);
8321
8931
  } catch {
8322
8932
  }
@@ -8401,11 +9011,11 @@ async function logout() {
8401
9011
 
8402
9012
  // src/commands/status.ts
8403
9013
  import { readFile as readFile16 } from "fs/promises";
8404
- import { basename as basename2, join as join27 } from "path";
9014
+ import { basename as basename2, join as join36 } from "path";
8405
9015
  async function status() {
8406
9016
  const configDir = getConfigDir2();
8407
- const STATE_PATH = join27(configDir, "listener-state.json");
8408
- const CONFIG_PATH = join27(configDir, "config.json");
9017
+ const STATE_PATH = join36(configDir, "listener-state.json");
9018
+ const CONFIG_PATH = join36(configDir, "config.json");
8409
9019
  let state = null;
8410
9020
  try {
8411
9021
  const data = await readFile16(STATE_PATH, "utf-8");
@@ -8453,7 +9063,7 @@ async function status() {
8453
9063
 
8454
9064
  // src/commands/sync.ts
8455
9065
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
8456
- import { dirname as dirname14, join as join28 } from "path";
9066
+ import { dirname as dirname15, join as join37 } from "path";
8457
9067
  import chalk9 from "chalk";
8458
9068
  import ora4 from "ora";
8459
9069
  var POLL_INTERVAL_MS2 = 3e3;
@@ -8602,7 +9212,7 @@ async function sync() {
8602
9212
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
8603
9213
  const files = listResult.data?.files ?? listResult.files ?? [];
8604
9214
  if (files.length > 0) {
8605
- const contextDir = join28(repoRoot, DEFAULT_CONTEXT_FOLDER3);
9215
+ const contextDir = join37(repoRoot, DEFAULT_CONTEXT_FOLDER3);
8606
9216
  mkdirSync3(contextDir, { recursive: true });
8607
9217
  let downloadedCount = 0;
8608
9218
  let failedCount = 0;
@@ -8616,8 +9226,8 @@ async function sync() {
8616
9226
  const response = await fetch(presignedUrl);
8617
9227
  if (response.ok) {
8618
9228
  const content = await response.text();
8619
- const filePath = join28(contextDir, file.fileName);
8620
- mkdirSync3(dirname14(filePath), { recursive: true });
9229
+ const filePath = join37(contextDir, file.fileName);
9230
+ mkdirSync3(dirname15(filePath), { recursive: true });
8621
9231
  writeFileSync4(filePath, content, "utf-8");
8622
9232
  downloadedCount++;
8623
9233
  } else {
@@ -8869,7 +9479,7 @@ async function config() {
8869
9479
  // src/commands/mcp-log.ts
8870
9480
  import { createDecipheriv as createDecipheriv2 } from "crypto";
8871
9481
  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";
9482
+ import { dirname as dirname16, join as join38 } from "path";
8873
9483
  var FLAG_FILE = "mcp-log.flag";
8874
9484
  var LOG_FILE = "mcp-log.jsonl.enc";
8875
9485
  var KEY_FILE = "mcp-log.key";
@@ -8877,10 +9487,10 @@ var ENDPOINT_FILE = "listener.endpoint";
8877
9487
  var IV_BYTES2 = 12;
8878
9488
  var TAG_BYTES2 = 16;
8879
9489
  function flagPath() {
8880
- return join29(getConfigDir2(), FLAG_FILE);
9490
+ return join38(getConfigDir2(), FLAG_FILE);
8881
9491
  }
8882
9492
  function logPath() {
8883
- return join29(getConfigDir2(), LOG_FILE);
9493
+ return join38(getConfigDir2(), LOG_FILE);
8884
9494
  }
8885
9495
  async function readFlag() {
8886
9496
  try {
@@ -8896,7 +9506,7 @@ async function readFlag() {
8896
9506
  }
8897
9507
  async function writeFlag(flag) {
8898
9508
  const path = flagPath();
8899
- await mkdir18(dirname15(path), { recursive: true });
9509
+ await mkdir18(dirname16(path), { recursive: true });
8900
9510
  await writeFile18(path, JSON.stringify(flag, null, 2), { encoding: "utf-8", mode: 384 });
8901
9511
  }
8902
9512
  async function showConsentPrompt() {
@@ -8967,14 +9577,14 @@ async function trySendConsentToServer() {
8967
9577
  let apiUrl = null;
8968
9578
  let token = null;
8969
9579
  try {
8970
- const body = await readFile17(join29(getConfigDir2(), "config.json"), "utf-8");
9580
+ const body = await readFile17(join38(getConfigDir2(), "config.json"), "utf-8");
8971
9581
  const parsed = JSON.parse(body);
8972
9582
  apiUrl = parsed.repos?.find((r) => Boolean(r.apiUrl))?.apiUrl ?? parsed.defaultApiUrl ?? null;
8973
9583
  } catch {
8974
9584
  return false;
8975
9585
  }
8976
9586
  try {
8977
- const body = await readFile17(join29(getConfigDir2(), "credentials.json"), "utf-8");
9587
+ const body = await readFile17(join38(getConfigDir2(), "credentials.json"), "utf-8");
8978
9588
  const parsed = JSON.parse(body);
8979
9589
  token = parsed.idToken ?? null;
8980
9590
  } catch {
@@ -9027,7 +9637,7 @@ async function mcpLogStatus() {
9027
9637
  process.stderr.write("Log size: no file yet\n");
9028
9638
  }
9029
9639
  try {
9030
- const endpointBody = await readFile17(join29(getConfigDir2(), ENDPOINT_FILE), "utf-8");
9640
+ const endpointBody = await readFile17(join38(getConfigDir2(), ENDPOINT_FILE), "utf-8");
9031
9641
  const match = /endpoint=([^\n]+)/.exec(endpointBody);
9032
9642
  process.stderr.write(`MCP endpoint: ${match?.[1] ?? "(malformed endpoint file)"}
9033
9643
  `);
@@ -9054,7 +9664,7 @@ Run \`repowise mcp-log on\` to grant consent and view them.
9054
9664
  const key = await readKey();
9055
9665
  if (!key) {
9056
9666
  process.stderr.write(
9057
- `No encryption key at ${join29(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
9667
+ `No encryption key at ${join38(getConfigDir2(), KEY_FILE)} \u2014 listener may not have started yet.
9058
9668
  `
9059
9669
  );
9060
9670
  return;
@@ -9130,7 +9740,7 @@ Run \`repowise mcp-log on\` to grant consent and view them.
9130
9740
  }
9131
9741
  async function readKey() {
9132
9742
  try {
9133
- const body = await readFile17(join29(getConfigDir2(), KEY_FILE), "utf-8");
9743
+ const body = await readFile17(join38(getConfigDir2(), KEY_FILE), "utf-8");
9134
9744
  const parsed = Buffer.from(body.trim(), "base64");
9135
9745
  if (parsed.length !== 32) return null;
9136
9746
  return parsed;
@@ -9173,8 +9783,8 @@ async function mcpLog(subcommand, flags = {}) {
9173
9783
  import chalk11 from "chalk";
9174
9784
 
9175
9785
  // src/lib/graph-loader.ts
9176
- import { promises as fs2 } from "fs";
9177
- import { join as join30, resolve as resolve2 } from "path";
9786
+ import { promises as fs12 } from "fs";
9787
+ import { join as join39, resolve as resolve2 } from "path";
9178
9788
  import { gunzipSync } from "zlib";
9179
9789
  var RELATIVE_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json";
9180
9790
  var GZIPPED_GRAPH_PATH = "repowise-context/.meta/dependency-graph.json.gz";
@@ -9191,8 +9801,8 @@ var GraphNotFoundError = class extends Error {
9191
9801
  var cache = /* @__PURE__ */ new Map();
9192
9802
  async function loadGraph(repoRoot = process.cwd()) {
9193
9803
  const root = resolve2(repoRoot);
9194
- const gzPath = join30(root, GZIPPED_GRAPH_PATH);
9195
- const plainPath = join30(root, RELATIVE_GRAPH_PATH);
9804
+ const gzPath = join39(root, GZIPPED_GRAPH_PATH);
9805
+ const plainPath = join39(root, RELATIVE_GRAPH_PATH);
9196
9806
  const cached = cache.get(root);
9197
9807
  if (cached) {
9198
9808
  return { graph: cached, path: plainPath, bytes: 0, parseMs: 0, fromCache: true };
@@ -9200,14 +9810,14 @@ async function loadGraph(repoRoot = process.cwd()) {
9200
9810
  let graphPath = null;
9201
9811
  let raw = null;
9202
9812
  try {
9203
- raw = await fs2.readFile(gzPath);
9813
+ raw = await fs12.readFile(gzPath);
9204
9814
  graphPath = gzPath;
9205
9815
  } catch (err) {
9206
9816
  if (err.code !== "ENOENT") throw err;
9207
9817
  }
9208
9818
  if (!raw) {
9209
9819
  try {
9210
- raw = await fs2.readFile(plainPath);
9820
+ raw = await fs12.readFile(plainPath);
9211
9821
  graphPath = plainPath;
9212
9822
  } catch (err) {
9213
9823
  if (err.code === "ENOENT") {
@@ -9606,14 +10216,14 @@ function registerQueryCommand(program2) {
9606
10216
  }
9607
10217
 
9608
10218
  // 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";
10219
+ import { promises as fs16 } from "fs";
10220
+ import { homedir as homedir8 } from "os";
10221
+ import { join as join43 } from "path";
9612
10222
  import chalk12 from "chalk";
9613
10223
 
9614
10224
  // src/lib/cleanup/marker-blocks.ts
9615
- import { promises as fs3 } from "fs";
9616
- import { join as join31 } from "path";
10225
+ import { promises as fs13 } from "fs";
10226
+ import { join as join40 } from "path";
9617
10227
  var MARKER_START = "<!-- repowise-start -->";
9618
10228
  var MARKER_END = "<!-- repowise-end -->";
9619
10229
  var CONTEXT_FILES = [
@@ -9629,7 +10239,7 @@ var CONTEXT_FILES = [
9629
10239
  async function stripMarkerBlock(filePath) {
9630
10240
  let raw;
9631
10241
  try {
9632
- raw = await fs3.readFile(filePath, "utf-8");
10242
+ raw = await fs13.readFile(filePath, "utf-8");
9633
10243
  } catch (err) {
9634
10244
  if (err.code === "ENOENT")
9635
10245
  return { path: filePath, status: "missing" };
@@ -9644,16 +10254,16 @@ async function stripMarkerBlock(filePath) {
9644
10254
  const after = raw.slice(endIdx + MARKER_END.length).replace(/^\n+/, "");
9645
10255
  const stripped = (before + (before && after ? "\n\n" : "") + after).trim();
9646
10256
  if (stripped.length === 0) {
9647
- await fs3.unlink(filePath);
10257
+ await fs13.unlink(filePath);
9648
10258
  return { path: filePath, status: "deleted" };
9649
10259
  }
9650
- await fs3.writeFile(filePath, stripped + "\n", "utf-8");
10260
+ await fs13.writeFile(filePath, stripped + "\n", "utf-8");
9651
10261
  return { path: filePath, status: "stripped" };
9652
10262
  }
9653
10263
  async function stripAllMarkerBlocks(repoRoot) {
9654
10264
  const out = [];
9655
10265
  for (const relative of CONTEXT_FILES) {
9656
- const full = join31(repoRoot, relative);
10266
+ const full = join40(repoRoot, relative);
9657
10267
  const result = await stripMarkerBlock(full).catch((err) => ({
9658
10268
  path: full,
9659
10269
  status: "untouched",
@@ -9665,25 +10275,25 @@ async function stripAllMarkerBlocks(repoRoot) {
9665
10275
  }
9666
10276
 
9667
10277
  // src/lib/cleanup/mcp-configs.ts
9668
- import { promises as fs4 } from "fs";
9669
- import { join as join32 } from "path";
10278
+ import { promises as fs14 } from "fs";
10279
+ import { join as join41 } from "path";
9670
10280
  function mcpConfigPaths(repoRoot, home) {
9671
10281
  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")
10282
+ join41(repoRoot, ".mcp.json"),
10283
+ join41(repoRoot, ".cursor", "mcp.json"),
10284
+ join41(repoRoot, ".vscode", "mcp.json"),
10285
+ join41(repoRoot, ".roo", "mcp.json"),
10286
+ join41(home, ".cline", "mcp.json"),
10287
+ join41(home, ".codeium", "windsurf", "mcp_config.json"),
10288
+ join41(home, ".gemini", "settings.json"),
10289
+ join41(home, ".codex", "mcp.json"),
10290
+ join41(home, ".roo", "mcp.json")
9681
10291
  ];
9682
10292
  }
9683
10293
  async function removeRepowiseFromConfig(path, serverName) {
9684
10294
  let raw;
9685
10295
  try {
9686
- raw = await fs4.readFile(path, "utf-8");
10296
+ raw = await fs14.readFile(path, "utf-8");
9687
10297
  } catch (err) {
9688
10298
  if (err.code === "ENOENT") return { path, status: "not-found" };
9689
10299
  return { path, status: "error", error: err.message };
@@ -9703,7 +10313,7 @@ async function removeRepowiseFromConfig(path, serverName) {
9703
10313
  } else {
9704
10314
  next.mcpServers = servers;
9705
10315
  }
9706
- await fs4.writeFile(path, JSON.stringify(next, null, 2) + "\n", "utf-8");
10316
+ await fs14.writeFile(path, JSON.stringify(next, null, 2) + "\n", "utf-8");
9707
10317
  return { path, status: "removed" };
9708
10318
  }
9709
10319
  async function removeAllMcpEntries(repoRoot, home, repoId) {
@@ -9716,17 +10326,17 @@ async function removeAllMcpEntries(repoRoot, home, repoId) {
9716
10326
  }
9717
10327
 
9718
10328
  // 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";
10329
+ import { promises as fs15 } from "fs";
10330
+ import { homedir as homedir7 } from "os";
10331
+ import { join as join42, resolve as resolve3 } from "path";
9722
10332
  async function clearLocalState(homeOverride) {
9723
- const home = homeOverride ?? homedir6();
9724
- const target = resolve3(join33(home, ".repowise"));
10333
+ const home = homeOverride ?? homedir7();
10334
+ const target = resolve3(join42(home, ".repowise"));
9725
10335
  if (target === resolve3(home) || !target.startsWith(resolve3(home))) {
9726
10336
  return { path: target, status: "error", error: "refused: not under home" };
9727
10337
  }
9728
10338
  try {
9729
- await fs5.rm(target, { recursive: true, force: false });
10339
+ await fs15.rm(target, { recursive: true, force: false });
9730
10340
  return { path: target, status: "removed" };
9731
10341
  } catch (err) {
9732
10342
  if (err.code === "ENOENT")
@@ -9756,7 +10366,7 @@ async function stopAndUninstallService(uninstaller) {
9756
10366
  // src/commands/uninstall.ts
9757
10367
  async function uninstall2(opts = {}) {
9758
10368
  const tier = opts.tier ?? "uninstall";
9759
- const home = opts.home ?? homedir7();
10369
+ const home = opts.home ?? homedir8();
9760
10370
  const repoRoot = opts.repoRoot ?? process.cwd();
9761
10371
  const loadRepoIds = opts.loadRepoIds ?? defaultLoadRepoIds;
9762
10372
  const report = { tier, removed: [], preserved: [], skipped: [] };
@@ -9765,7 +10375,7 @@ async function uninstall2(opts = {}) {
9765
10375
  else if (svc.error) report.skipped.push({ path: "listener service", reason: svc.error });
9766
10376
  if (tier === "stop") return report;
9767
10377
  try {
9768
- await fs6.unlink(join34(home, ".repowise", "credentials.json"));
10378
+ await fs16.unlink(join43(home, ".repowise", "credentials.json"));
9769
10379
  report.removed.push("credentials");
9770
10380
  } catch (err) {
9771
10381
  if (err.code !== "ENOENT") {
@@ -9792,7 +10402,7 @@ async function uninstall2(opts = {}) {
9792
10402
  const allPaths = mcpConfigPaths(repoRoot, home);
9793
10403
  for (const p of allPaths) {
9794
10404
  try {
9795
- await fs6.access(p);
10405
+ await fs16.access(p);
9796
10406
  } catch {
9797
10407
  }
9798
10408
  }
@@ -9804,7 +10414,7 @@ async function uninstall2(opts = {}) {
9804
10414
  }
9805
10415
  async function defaultLoadRepoIds(home) {
9806
10416
  try {
9807
- const raw = await fs6.readFile(join34(home, ".repowise", "config.json"), "utf-8");
10417
+ const raw = await fs16.readFile(join43(home, ".repowise", "config.json"), "utf-8");
9808
10418
  const parsed = JSON.parse(raw);
9809
10419
  return (parsed.repos ?? []).map((r) => r.repoId);
9810
10420
  } catch {
@@ -9850,13 +10460,13 @@ Done \u2014 ${report.removed.length} removed, ${report.skipped.length} skipped.
9850
10460
  }
9851
10461
 
9852
10462
  // src/commands/mcp-shim.ts
9853
- import { promises as fs7 } from "fs";
10463
+ import { promises as fs17 } from "fs";
9854
10464
  import { createInterface as createInterface2 } from "readline";
9855
- import { homedir as homedir8 } from "os";
9856
- import { join as join35 } from "path";
10465
+ import { homedir as homedir9 } from "os";
10466
+ import { join as join44 } from "path";
9857
10467
  var DEFAULT_MAX = 200 * 1024;
9858
10468
  async function mcpShim(opts) {
9859
- const endpointPath = opts.endpointFile ?? join35(homedir8(), ".repowise", "listener.endpoint");
10469
+ const endpointPath = opts.endpointFile ?? join44(homedir9(), ".repowise", "listener.endpoint");
9860
10470
  const stdin = opts.stdin ?? process.stdin;
9861
10471
  const stdout = opts.stdout ?? process.stdout;
9862
10472
  const stderr = opts.stderr ?? process.stderr;
@@ -9927,7 +10537,7 @@ async function mcpShim(opts) {
9927
10537
  }
9928
10538
  async function readEndpoint(path) {
9929
10539
  try {
9930
- const raw = (await fs7.readFile(path, "utf-8")).trim();
10540
+ const raw = (await fs17.readFile(path, "utf-8")).trim();
9931
10541
  if (!raw) return null;
9932
10542
  if (raw.startsWith("http://") || raw.startsWith("https://")) {
9933
10543
  return { endpoint: raw.split("\n")[0].trim(), secret: null };
@@ -10141,14 +10751,14 @@ function writeError(stream, id, code, message) {
10141
10751
 
10142
10752
  // src/commands/lsp.ts
10143
10753
  init_registry();
10144
- import { spawn as spawn3 } from "child_process";
10754
+ import { spawn as spawn4 } from "child_process";
10145
10755
  import chalk13 from "chalk";
10146
10756
  async function isOnPath(command) {
10147
10757
  if (/[^\w./+-]/.test(command)) return false;
10148
10758
  const isWin = process.platform === "win32";
10149
10759
  const probeCmd = isWin ? "where" : "which";
10150
10760
  return new Promise((resolve4) => {
10151
- const child = spawn3(probeCmd, [command], { stdio: "ignore" });
10761
+ const child = spawn4(probeCmd, [command], { stdio: "ignore" });
10152
10762
  child.on("close", (code) => {
10153
10763
  resolve4(code === 0);
10154
10764
  });
@@ -10209,8 +10819,8 @@ async function lspDoctor() {
10209
10819
 
10210
10820
  // bin/repowise.ts
10211
10821
  var __filename = fileURLToPath4(import.meta.url);
10212
- var __dirname = dirname16(__filename);
10213
- var pkg = JSON.parse(readFileSync3(join36(__dirname, "..", "..", "package.json"), "utf-8"));
10822
+ var __dirname = dirname17(__filename);
10823
+ var pkg = JSON.parse(readFileSync3(join45(__dirname, "..", "..", "package.json"), "utf-8"));
10214
10824
  var program = new Command();
10215
10825
  program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
10216
10826
  await showWelcome(pkg.version);