@modwrench/workbench 0.0.1

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 (121) hide show
  1. package/data/conflicts/README.md +39 -0
  2. package/data/conflicts/fallout4.json +1 -0
  3. package/data/conflicts/lethalcompany.json +1 -0
  4. package/data/conflicts/skyrimspecialedition.json +1 -0
  5. package/dist/conflicts/community.d.ts +3 -0
  6. package/dist/conflicts/community.d.ts.map +1 -0
  7. package/dist/conflicts/community.js +96 -0
  8. package/dist/conflicts/community.js.map +1 -0
  9. package/dist/conflicts/index.d.ts +6 -0
  10. package/dist/conflicts/index.d.ts.map +1 -0
  11. package/dist/conflicts/index.js +114 -0
  12. package/dist/conflicts/index.js.map +1 -0
  13. package/dist/conflicts/loot.d.ts +19 -0
  14. package/dist/conflicts/loot.d.ts.map +1 -0
  15. package/dist/conflicts/loot.js +148 -0
  16. package/dist/conflicts/loot.js.map +1 -0
  17. package/dist/conflicts/types.d.ts +31 -0
  18. package/dist/conflicts/types.d.ts.map +1 -0
  19. package/dist/conflicts/types.js +6 -0
  20. package/dist/conflicts/types.js.map +1 -0
  21. package/dist/crashlog/bepinex.d.ts +3 -0
  22. package/dist/crashlog/bepinex.d.ts.map +1 -0
  23. package/dist/crashlog/bepinex.js +105 -0
  24. package/dist/crashlog/bepinex.js.map +1 -0
  25. package/dist/crashlog/crashlogger-sse.d.ts +3 -0
  26. package/dist/crashlog/crashlogger-sse.d.ts.map +1 -0
  27. package/dist/crashlog/crashlogger-sse.js +226 -0
  28. package/dist/crashlog/crashlogger-sse.js.map +1 -0
  29. package/dist/crashlog/detect.d.ts +3 -0
  30. package/dist/crashlog/detect.d.ts.map +1 -0
  31. package/dist/crashlog/detect.js +44 -0
  32. package/dist/crashlog/detect.js.map +1 -0
  33. package/dist/crashlog/index.d.ts +15 -0
  34. package/dist/crashlog/index.d.ts.map +1 -0
  35. package/dist/crashlog/index.js +65 -0
  36. package/dist/crashlog/index.js.map +1 -0
  37. package/dist/crashlog/minecraft.d.ts +3 -0
  38. package/dist/crashlog/minecraft.d.ts.map +1 -0
  39. package/dist/crashlog/minecraft.js +145 -0
  40. package/dist/crashlog/minecraft.js.map +1 -0
  41. package/dist/crashlog/netscriptframework.d.ts +3 -0
  42. package/dist/crashlog/netscriptframework.d.ts.map +1 -0
  43. package/dist/crashlog/netscriptframework.js +109 -0
  44. package/dist/crashlog/netscriptframework.js.map +1 -0
  45. package/dist/crashlog/types.d.ts +35 -0
  46. package/dist/crashlog/types.d.ts.map +1 -0
  47. package/dist/crashlog/types.js +9 -0
  48. package/dist/crashlog/types.js.map +1 -0
  49. package/dist/detect/environment.d.ts +35 -0
  50. package/dist/detect/environment.d.ts.map +1 -0
  51. package/dist/detect/environment.js +65 -0
  52. package/dist/detect/environment.js.map +1 -0
  53. package/dist/detect/games.d.ts +21 -0
  54. package/dist/detect/games.d.ts.map +1 -0
  55. package/dist/detect/games.js +159 -0
  56. package/dist/detect/games.js.map +1 -0
  57. package/dist/detect/loader.d.ts +12 -0
  58. package/dist/detect/loader.d.ts.map +1 -0
  59. package/dist/detect/loader.js +20 -0
  60. package/dist/detect/loader.js.map +1 -0
  61. package/dist/detect/manager.d.ts +26 -0
  62. package/dist/detect/manager.d.ts.map +1 -0
  63. package/dist/detect/manager.js +157 -0
  64. package/dist/detect/manager.js.map +1 -0
  65. package/dist/detect/os.d.ts +21 -0
  66. package/dist/detect/os.d.ts.map +1 -0
  67. package/dist/detect/os.js +58 -0
  68. package/dist/detect/os.js.map +1 -0
  69. package/dist/detect/steam.d.ts +32 -0
  70. package/dist/detect/steam.d.ts.map +1 -0
  71. package/dist/detect/steam.js +155 -0
  72. package/dist/detect/steam.js.map +1 -0
  73. package/dist/detect/vdf.d.ts +12 -0
  74. package/dist/detect/vdf.d.ts.map +1 -0
  75. package/dist/detect/vdf.js +112 -0
  76. package/dist/detect/vdf.js.map +1 -0
  77. package/dist/index.d.ts +3 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +27 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/loadorder/index.d.ts +20 -0
  82. package/dist/loadorder/index.d.ts.map +1 -0
  83. package/dist/loadorder/index.js +76 -0
  84. package/dist/loadorder/index.js.map +1 -0
  85. package/dist/loadorder/mo2.d.ts +21 -0
  86. package/dist/loadorder/mo2.d.ts.map +1 -0
  87. package/dist/loadorder/mo2.js +201 -0
  88. package/dist/loadorder/mo2.js.map +1 -0
  89. package/dist/loadorder/r2modman.d.ts +12 -0
  90. package/dist/loadorder/r2modman.d.ts.map +1 -0
  91. package/dist/loadorder/r2modman.js +115 -0
  92. package/dist/loadorder/r2modman.js.map +1 -0
  93. package/dist/loadorder/types.d.ts +30 -0
  94. package/dist/loadorder/types.d.ts.map +1 -0
  95. package/dist/loadorder/types.js +5 -0
  96. package/dist/loadorder/types.js.map +1 -0
  97. package/dist/loadorder/vortex.d.ts +8 -0
  98. package/dist/loadorder/vortex.d.ts.map +1 -0
  99. package/dist/loadorder/vortex.js +77 -0
  100. package/dist/loadorder/vortex.js.map +1 -0
  101. package/dist/metadata/clients.d.ts +11 -0
  102. package/dist/metadata/clients.d.ts.map +1 -0
  103. package/dist/metadata/clients.js +90 -0
  104. package/dist/metadata/clients.js.map +1 -0
  105. package/dist/metadata/index.d.ts +3 -0
  106. package/dist/metadata/index.d.ts.map +1 -0
  107. package/dist/metadata/index.js +149 -0
  108. package/dist/metadata/index.js.map +1 -0
  109. package/dist/metadata/normalize.d.ts +43 -0
  110. package/dist/metadata/normalize.d.ts.map +1 -0
  111. package/dist/metadata/normalize.js +88 -0
  112. package/dist/metadata/normalize.js.map +1 -0
  113. package/dist/metadata/types.d.ts +57 -0
  114. package/dist/metadata/types.d.ts.map +1 -0
  115. package/dist/metadata/types.js +9 -0
  116. package/dist/metadata/types.js.map +1 -0
  117. package/dist/register.d.ts +13 -0
  118. package/dist/register.d.ts.map +1 -0
  119. package/dist/register.js +209 -0
  120. package/dist/register.js.map +1 -0
  121. package/package.json +58 -0
@@ -0,0 +1,109 @@
1
+ // NetScriptFramework crash logs are older Skyrim / Skyrim LE territory. The
2
+ // format is line-oriented with explicit field labels rather than the section
3
+ // blocks Crash Logger SSE uses. Common fields:
4
+ // NetScriptFramework Crash Log
5
+ // Crash Reason: AccessViolationException reading address 0x0
6
+ // Application: SkyrimSE.exe
7
+ // Version: 1.5.97.0
8
+ // Crashed thread is main thread: True
9
+ //
10
+ // Then a "Call Stack:" block followed by frames, and "Loaded Plugins:" with
11
+ // indexed plugins similar to CL SSE.
12
+ const KV_REGEX = /^([A-Za-z][A-Za-z0-9 ]+):\s*(.*)$/;
13
+ export function parseNetScriptFramework(text) {
14
+ const lines = text.split(/\r?\n/);
15
+ const fields = {};
16
+ const callStack = [];
17
+ const loadedPlugins = [];
18
+ const rawSections = {};
19
+ let mode = "header";
20
+ let bufferKey = null;
21
+ let buffer = [];
22
+ const flushBuffer = () => {
23
+ if (bufferKey)
24
+ rawSections[bufferKey] = buffer.join("\n").trim();
25
+ bufferKey = null;
26
+ buffer = [];
27
+ };
28
+ for (const raw of lines) {
29
+ const line = raw.trimEnd();
30
+ if (line.endsWith(":") && line.length < 60) {
31
+ flushBuffer();
32
+ const label = line.slice(0, -1).trim();
33
+ if (/call.?stack/i.test(label))
34
+ mode = "callstack";
35
+ else if (/plugins/i.test(label))
36
+ mode = "plugins";
37
+ else {
38
+ mode = "other";
39
+ bufferKey = label;
40
+ }
41
+ continue;
42
+ }
43
+ if (mode === "callstack") {
44
+ const stripped = line.trim();
45
+ if (!stripped)
46
+ continue;
47
+ const match = stripped.match(/^(?:\(\d+\)\s+)?(0x[0-9A-Fa-f]+)\s+\(?([^)\s]+)\)?(?:\s*([+:]\s*\S+))?(?:\s+(.+))?$/);
48
+ if (match) {
49
+ const frame = {
50
+ module: match[2] ?? "(unknown)",
51
+ };
52
+ if (match[3])
53
+ frame.offset = match[3].replace(/[+:\s]/g, "");
54
+ if (match[4])
55
+ frame.function = match[4].trim();
56
+ callStack.push(frame);
57
+ }
58
+ continue;
59
+ }
60
+ if (mode === "plugins") {
61
+ const stripped = line.trim();
62
+ if (!stripped)
63
+ continue;
64
+ const match = stripped.match(/^\(?([0-9A-F]{2})\)?\s+(.+)$/);
65
+ if (match) {
66
+ loadedPlugins.push({
67
+ loadIndex: match[1],
68
+ name: (match[2] ?? "").trim(),
69
+ });
70
+ }
71
+ continue;
72
+ }
73
+ if (mode === "header") {
74
+ const kv = line.match(KV_REGEX);
75
+ if (kv && kv[1] && kv[2] !== undefined) {
76
+ fields[kv[1].trim()] = kv[2].trim();
77
+ continue;
78
+ }
79
+ }
80
+ if (mode === "other" && bufferKey) {
81
+ buffer.push(raw);
82
+ }
83
+ }
84
+ flushBuffer();
85
+ const exception = {};
86
+ const reason = fields["Crash Reason"];
87
+ if (reason) {
88
+ const typeMatch = reason.match(/^([A-Za-z]+Exception)/);
89
+ if (typeMatch)
90
+ exception.type = typeMatch[1];
91
+ const addrMatch = reason.match(/(0x[0-9A-Fa-f]+)/);
92
+ if (addrMatch)
93
+ exception.address = addrMatch[1];
94
+ exception.description = reason;
95
+ }
96
+ const result = {
97
+ detectedType: "netscriptframework",
98
+ exception,
99
+ callStack,
100
+ loadedPlugins,
101
+ rawSections,
102
+ };
103
+ const version = fields["Version"];
104
+ const app = fields["Application"];
105
+ if (version && app)
106
+ result.gameVersion = `${app} v${version}`;
107
+ return result;
108
+ }
109
+ //# sourceMappingURL=netscriptframework.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"netscriptframework.js","sourceRoot":"","sources":["../../src/crashlog/netscriptframework.ts"],"names":[],"mappings":"AAMA,4EAA4E;AAC5E,6EAA6E;AAC7E,+CAA+C;AAC/C,iCAAiC;AACjC,+DAA+D;AAC/D,8BAA8B;AAC9B,sBAAsB;AACtB,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,qCAAqC;AAErC,MAAM,QAAQ,GAAG,mCAAmC,CAAC;AAErD,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAElC,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,MAAM,SAAS,GAAqB,EAAE,CAAC;IACvC,MAAM,aAAa,GAAmB,EAAE,CAAC;IACzC,MAAM,WAAW,GAA2B,EAAE,CAAC;IAE/C,IAAI,IAAI,GAAiD,QAAQ,CAAC;IAClE,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,IAAI,MAAM,GAAa,EAAE,CAAC;IAE1B,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,IAAI,SAAS;YAAE,WAAW,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACjE,SAAS,GAAG,IAAI,CAAC;QACjB,MAAM,GAAG,EAAE,CAAC;IACd,CAAC,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC;QAE3B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YAC3C,WAAW,EAAE,CAAC;YACd,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACvC,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,IAAI,GAAG,WAAW,CAAC;iBAC9C,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,IAAI,GAAG,SAAS,CAAC;iBAC7C,CAAC;gBACJ,IAAI,GAAG,OAAO,CAAC;gBACf,SAAS,GAAG,KAAK,CAAC;YACpB,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ;gBAAE,SAAS;YACxB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAC1B,qFAAqF,CACtF,CAAC;YACF,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,KAAK,GAAmB;oBAC5B,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,WAAW;iBAChC,CAAC;gBACF,IAAI,KAAK,CAAC,CAAC,CAAC;oBAAE,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBAC7D,IAAI,KAAK,CAAC,CAAC,CAAC;oBAAE,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC/C,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ;gBAAE,SAAS;YACxB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAC7D,IAAI,KAAK,EAAE,CAAC;gBACV,aAAa,CAAC,IAAI,CAAC;oBACjB,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;oBACnB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;iBAC9B,CAAC,CAAC;YACL,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAChC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;gBACvC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACpC,SAAS;YACX,CAAC;QACH,CAAC;QAED,IAAI,IAAI,KAAK,OAAO,IAAI,SAAS,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,WAAW,EAAE,CAAC;IAEd,MAAM,SAAS,GAAqC,EAAE,CAAC;IACvD,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IACtC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACxD,IAAI,SAAS;YAAE,SAAS,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACnD,IAAI,SAAS;YAAE,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAChD,SAAS,CAAC,WAAW,GAAG,MAAM,CAAC;IACjC,CAAC;IAED,MAAM,MAAM,GAAwB;QAClC,YAAY,EAAE,oBAAoB;QAClC,SAAS;QACT,SAAS;QACT,aAAa;QACb,WAAW;KACZ,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC;IAClC,IAAI,OAAO,IAAI,GAAG;QAAE,MAAM,CAAC,WAAW,GAAG,GAAG,GAAG,KAAK,OAAO,EAAE,CAAC;IAC9D,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,35 @@
1
+ export type CrashlogType = "crashlogger-sse" | "buffout4" | "netscriptframework" | "bepinex" | "minecraft" | "unknown";
2
+ export type CallStackFrame = {
3
+ index?: number;
4
+ module: string;
5
+ function?: string;
6
+ offset?: string;
7
+ };
8
+ export type LoadedPlugin = {
9
+ name: string;
10
+ loadIndex?: string;
11
+ };
12
+ export type SuspectedRef = {
13
+ type: string;
14
+ value: string;
15
+ /** Best-effort guess at originating mod. Never present as certainty. */
16
+ likelySource?: string;
17
+ };
18
+ export type CrashlogParseResult = {
19
+ detectedType: CrashlogType;
20
+ gameVersion?: string;
21
+ loggerVersion?: string;
22
+ timestamp?: string;
23
+ exception: {
24
+ type?: string;
25
+ address?: string;
26
+ description?: string;
27
+ };
28
+ callStack: CallStackFrame[];
29
+ loadedPlugins: LoadedPlugin[];
30
+ registers?: Record<string, string>;
31
+ suspectedRefs?: SuspectedRef[];
32
+ /** Raw text of each section the parser recognized but didn't structure. */
33
+ rawSections: Record<string, string>;
34
+ };
35
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/crashlog/types.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,YAAY,GACpB,iBAAiB,GACjB,UAAU,GACV,oBAAoB,GACpB,SAAS,GACT,WAAW,GACX,SAAS,CAAC;AAEd,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC,CAAC"}
@@ -0,0 +1,9 @@
1
+ // Normalized cross-format crashlog parse output. Every parser emits this
2
+ // shape so the downstream LLM-reasoning step doesn't care whether the source
3
+ // was Crash Logger SSE, Buffout 4, BepInEx, NetScriptFramework, or Minecraft.
4
+ //
5
+ // Critical design rule: this module does PARSING only. No diagnosis, no
6
+ // suggested causes, no "you should disable mod X" advice. That's the LLM's
7
+ // job — we just feed it structured facts.
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/crashlog/types.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,6EAA6E;AAC7E,8EAA8E;AAC9E,EAAE;AACF,wEAAwE;AACxE,2EAA2E;AAC3E,0CAA0C"}
@@ -0,0 +1,35 @@
1
+ import { type OsName } from "./os.js";
2
+ import { type GameDef } from "./games.js";
3
+ import { type ManagerName } from "./manager.js";
4
+ export type DetectedGame = {
5
+ gameId: string;
6
+ gameName: string;
7
+ installPath: string;
8
+ family: GameDef["family"];
9
+ modManager: ManagerName | "none";
10
+ modLoader: string;
11
+ protonVersion?: string;
12
+ };
13
+ export type DetectEnvironmentResult = {
14
+ os: OsName;
15
+ isSteamDeck: boolean;
16
+ steamDeckMode?: "game" | "desktop";
17
+ steamRoot: string | null;
18
+ installedModManagers: Array<{
19
+ name: ManagerName;
20
+ dataPath: string;
21
+ managedGameIds?: string[];
22
+ }>;
23
+ detectedGames: DetectedGame[];
24
+ availableProton?: string[];
25
+ };
26
+ /**
27
+ * Single-pass detection of the user's modding setup. Pure read-only —
28
+ * filesystem checks plus Steam's libraryfolders.vdf. No network, no writes.
29
+ *
30
+ * Extracted from the original mw_detect_environment tool handler so that
31
+ * @modwrench/cli's MetaCatalog can also drive activation decisions off the
32
+ * same detection logic without duplicating it.
33
+ */
34
+ export declare function detectEnvironment(): DetectEnvironmentResult;
35
+ //# sourceMappingURL=environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../src/detect/environment.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,MAAM,EACZ,MAAM,SAAS,CAAC;AAQjB,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAEvD,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1B,UAAU,EAAE,WAAW,GAAG,MAAM,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oBAAoB,EAAE,KAAK,CAAC;QAC1B,IAAI,EAAE,WAAW,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;KAC3B,CAAC,CAAC;IACH,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,IAAI,uBAAuB,CAoD3D"}
@@ -0,0 +1,65 @@
1
+ import { detectOs, detectSteamDeck, detectGameMode, } from "./os.js";
2
+ import { findSteamRoot, findSteamLibraries, findInstalledApp, listProtonTools, detectProtonForApp, } from "./steam.js";
3
+ import { KNOWN_GAMES } from "./games.js";
4
+ import { detectModLoader } from "./loader.js";
5
+ import { detectInstalledManagers, inferManagerForGame, } from "./manager.js";
6
+ /**
7
+ * Single-pass detection of the user's modding setup. Pure read-only —
8
+ * filesystem checks plus Steam's libraryfolders.vdf. No network, no writes.
9
+ *
10
+ * Extracted from the original mw_detect_environment tool handler so that
11
+ * @modwrench/cli's MetaCatalog can also drive activation decisions off the
12
+ * same detection logic without duplicating it.
13
+ */
14
+ export function detectEnvironment() {
15
+ const os = detectOs();
16
+ const isSteamDeck = detectSteamDeck();
17
+ const isGameMode = detectGameMode();
18
+ const steamRoot = findSteamRoot();
19
+ const managers = detectInstalledManagers();
20
+ const detectedGames = [];
21
+ if (steamRoot) {
22
+ const libraries = findSteamLibraries(steamRoot);
23
+ for (const game of KNOWN_GAMES) {
24
+ const app = findInstalledApp(libraries, game.steamAppId);
25
+ if (!app)
26
+ continue;
27
+ const loader = detectModLoader(app.installDir, game);
28
+ const manager = inferManagerForGame(game, managers) ?? "none";
29
+ const proton = detectProtonForApp(steamRoot, game.steamAppId);
30
+ const entry = {
31
+ gameId: game.gameId,
32
+ gameName: app.name,
33
+ installPath: app.installDir,
34
+ family: game.family,
35
+ modManager: manager,
36
+ modLoader: loader,
37
+ };
38
+ if (proton)
39
+ entry.protonVersion = proton;
40
+ detectedGames.push(entry);
41
+ }
42
+ }
43
+ const protonTools = os === "linux" && steamRoot ? listProtonTools(steamRoot) : [];
44
+ const result = {
45
+ os,
46
+ isSteamDeck,
47
+ steamRoot,
48
+ installedModManagers: managers.map((m) => {
49
+ const entry = {
50
+ name: m.name,
51
+ dataPath: m.dataPath,
52
+ };
53
+ if (m.managedGameIds)
54
+ entry.managedGameIds = m.managedGameIds;
55
+ return entry;
56
+ }),
57
+ detectedGames,
58
+ };
59
+ if (isSteamDeck)
60
+ result.steamDeckMode = isGameMode ? "game" : "desktop";
61
+ if (protonTools.length > 0)
62
+ result.availableProton = protonTools;
63
+ return result;
64
+ }
65
+ //# sourceMappingURL=environment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.js","sourceRoot":"","sources":["../../src/detect/environment.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,eAAe,EACf,cAAc,GAEf,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,uBAAuB,EACvB,mBAAmB,GAGpB,MAAM,cAAc,CAAC;AA0BtB;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IACtB,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAsB,uBAAuB,EAAE,CAAC;IAE9D,MAAM,aAAa,GAAmB,EAAE,CAAC;IAEzC,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,SAAS,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;QAChD,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YACzD,IAAI,CAAC,GAAG;gBAAE,SAAS;YACnB,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YACrD,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC;YAC9D,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAC9D,MAAM,KAAK,GAAiB;gBAC1B,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,QAAQ,EAAE,GAAG,CAAC,IAAI;gBAClB,WAAW,EAAE,GAAG,CAAC,UAAU;gBAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,UAAU,EAAE,OAAO;gBACnB,SAAS,EAAE,MAAM;aAClB,CAAC;YACF,IAAI,MAAM;gBAAE,KAAK,CAAC,aAAa,GAAG,MAAM,CAAC;YACzC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GACf,EAAE,KAAK,OAAO,IAAI,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEhE,MAAM,MAAM,GAA4B;QACtC,EAAE;QACF,WAAW;QACX,SAAS;QACT,oBAAoB,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACvC,MAAM,KAAK,GAAuE;gBAChF,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;aACrB,CAAC;YACF,IAAI,CAAC,CAAC,cAAc;gBAAE,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,cAAc,CAAC;YAC9D,OAAO,KAAK,CAAC;QACf,CAAC,CAAC;QACF,aAAa;KACd,CAAC;IAEF,IAAI,WAAW;QAAE,MAAM,CAAC,aAAa,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACxE,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,eAAe,GAAG,WAAW,CAAC;IAEjE,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,21 @@
1
+ export type GameId = "skyrimspecialedition" | "skyrim" | "skyrimvr" | "fallout4" | "fallout4vr" | "falloutnv" | "fallout3" | "starfield" | "oblivion" | "lethalcompany" | "valheim" | "repo" | "riskofrain2" | "dysonsphereprogram" | "boneworks" | "thesims4";
2
+ export type GameDef = {
3
+ gameId: GameId;
4
+ steamAppId: string;
5
+ displayName: string;
6
+ family: "bethesda" | "unity-coop" | "minecraft" | "sims" | "other";
7
+ /** Mod loaders the game can use. First match wins during detection. */
8
+ loaderChecks: Array<{
9
+ loader: ModLoader;
10
+ /** Files to look for inside the game's install directory, relative paths. */
11
+ files: string[];
12
+ }>;
13
+ /** Folder name r2modman uses for this game's profiles, if it supports it. */
14
+ r2modmanFolder?: string;
15
+ /** Substrings that may appear in MO2's ModOrganizer.ini gameName field. */
16
+ mo2GameNames?: string[];
17
+ };
18
+ export declare function findGameById(gameId: string): GameDef | undefined;
19
+ export type ModLoader = "skse" | "f4se" | "sfse" | "nvse" | "fose" | "obse" | "bepinex-5" | "bepinex-6-mono" | "bepinex-6-il2cpp" | "melonloader" | "forge" | "fabric" | "neoforge" | "none";
20
+ export declare const KNOWN_GAMES: GameDef[];
21
+ //# sourceMappingURL=games.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"games.d.ts","sourceRoot":"","sources":["../../src/detect/games.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,MAAM,GACd,sBAAsB,GACtB,QAAQ,GACR,UAAU,GACV,UAAU,GACV,YAAY,GACZ,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,eAAe,GACf,SAAS,GACT,MAAM,GACN,aAAa,GACb,oBAAoB,GACpB,WAAW,GACX,UAAU,CAAC;AAEf,MAAM,MAAM,OAAO,GAAG;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;IACnE,uEAAuE;IACvE,YAAY,EAAE,KAAK,CAAC;QAClB,MAAM,EAAE,SAAS,CAAC;QAClB,6EAA6E;QAC7E,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC,CAAC;IACH,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AAEF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAEhE;AAED,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,GACN,WAAW,GACX,gBAAgB,GAChB,kBAAkB,GAClB,aAAa,GACb,OAAO,GACP,QAAQ,GACR,UAAU,GACV,MAAM,CAAC;AAEX,eAAO,MAAM,WAAW,EAAE,OAAO,EAoJhC,CAAC"}
@@ -0,0 +1,159 @@
1
+ // Catalogue of mod-friendly games we know how to recognize. Keep this list
2
+ // pragmatic — coverage of the communities ModWrench targets, not every game
3
+ // on Steam. New entries should be drive-by additions, no code changes needed.
4
+ //
5
+ // gameId follows Nexus's domain_name convention where possible so it can be
6
+ // passed straight to nexus_get_game and friends without translation.
7
+ export function findGameById(gameId) {
8
+ return KNOWN_GAMES.find((g) => g.gameId === gameId);
9
+ }
10
+ export const KNOWN_GAMES = [
11
+ {
12
+ gameId: "skyrimspecialedition",
13
+ steamAppId: "489830",
14
+ displayName: "The Elder Scrolls V: Skyrim Special Edition",
15
+ family: "bethesda",
16
+ loaderChecks: [{ loader: "skse", files: ["skse64_loader.exe"] }],
17
+ mo2GameNames: ["Skyrim Special Edition", "Skyrim SE"],
18
+ },
19
+ {
20
+ gameId: "skyrim",
21
+ steamAppId: "72850",
22
+ displayName: "The Elder Scrolls V: Skyrim",
23
+ family: "bethesda",
24
+ loaderChecks: [{ loader: "skse", files: ["skse_loader.exe"] }],
25
+ mo2GameNames: ["Skyrim", "Skyrim Legendary Edition"],
26
+ },
27
+ {
28
+ gameId: "skyrimvr",
29
+ steamAppId: "611670",
30
+ displayName: "Skyrim VR",
31
+ family: "bethesda",
32
+ loaderChecks: [{ loader: "skse", files: ["sksevr_loader.exe"] }],
33
+ mo2GameNames: ["Skyrim VR"],
34
+ },
35
+ {
36
+ gameId: "fallout4",
37
+ steamAppId: "377160",
38
+ displayName: "Fallout 4",
39
+ family: "bethesda",
40
+ loaderChecks: [{ loader: "f4se", files: ["f4se_loader.exe"] }],
41
+ mo2GameNames: ["Fallout 4"],
42
+ },
43
+ {
44
+ gameId: "fallout4vr",
45
+ steamAppId: "611660",
46
+ displayName: "Fallout 4 VR",
47
+ family: "bethesda",
48
+ loaderChecks: [{ loader: "f4se", files: ["f4sevr_loader.exe"] }],
49
+ mo2GameNames: ["Fallout 4 VR"],
50
+ },
51
+ {
52
+ gameId: "falloutnv",
53
+ steamAppId: "22380",
54
+ displayName: "Fallout: New Vegas",
55
+ family: "bethesda",
56
+ loaderChecks: [{ loader: "nvse", files: ["nvse_loader.exe"] }],
57
+ mo2GameNames: ["New Vegas", "Fallout New Vegas"],
58
+ },
59
+ {
60
+ gameId: "fallout3",
61
+ steamAppId: "22300",
62
+ displayName: "Fallout 3",
63
+ family: "bethesda",
64
+ loaderChecks: [{ loader: "fose", files: ["fose_loader.exe"] }],
65
+ mo2GameNames: ["Fallout 3"],
66
+ },
67
+ {
68
+ gameId: "starfield",
69
+ steamAppId: "1716740",
70
+ displayName: "Starfield",
71
+ family: "bethesda",
72
+ loaderChecks: [{ loader: "sfse", files: ["sfse_loader.exe"] }],
73
+ mo2GameNames: ["Starfield"],
74
+ },
75
+ {
76
+ gameId: "oblivion",
77
+ steamAppId: "22330",
78
+ displayName: "The Elder Scrolls IV: Oblivion",
79
+ family: "bethesda",
80
+ loaderChecks: [{ loader: "obse", files: ["obse_loader.exe"] }],
81
+ mo2GameNames: ["Oblivion"],
82
+ },
83
+ {
84
+ gameId: "lethalcompany",
85
+ steamAppId: "1966720",
86
+ displayName: "Lethal Company",
87
+ family: "unity-coop",
88
+ loaderChecks: [
89
+ {
90
+ loader: "bepinex-5",
91
+ files: ["BepInEx/core/BepInEx.dll", "winhttp.dll"],
92
+ },
93
+ ],
94
+ r2modmanFolder: "LethalCompany",
95
+ },
96
+ {
97
+ gameId: "valheim",
98
+ steamAppId: "892970",
99
+ displayName: "Valheim",
100
+ family: "unity-coop",
101
+ loaderChecks: [
102
+ { loader: "bepinex-5", files: ["BepInEx/core/BepInEx.dll"] },
103
+ ],
104
+ r2modmanFolder: "Valheim",
105
+ },
106
+ {
107
+ gameId: "repo",
108
+ steamAppId: "3241660",
109
+ displayName: "R.E.P.O.",
110
+ family: "unity-coop",
111
+ loaderChecks: [
112
+ {
113
+ loader: "bepinex-6-il2cpp",
114
+ files: ["BepInEx/core/BepInEx.Unity.IL2CPP.dll"],
115
+ },
116
+ { loader: "bepinex-5", files: ["BepInEx/core/BepInEx.dll"] },
117
+ ],
118
+ r2modmanFolder: "REPO",
119
+ },
120
+ {
121
+ gameId: "riskofrain2",
122
+ steamAppId: "632360",
123
+ displayName: "Risk of Rain 2",
124
+ family: "unity-coop",
125
+ loaderChecks: [
126
+ { loader: "bepinex-5", files: ["BepInEx/core/BepInEx.dll"] },
127
+ ],
128
+ r2modmanFolder: "RiskOfRain2",
129
+ },
130
+ {
131
+ gameId: "dysonsphereprogram",
132
+ steamAppId: "1366540",
133
+ displayName: "Dyson Sphere Program",
134
+ family: "unity-coop",
135
+ loaderChecks: [
136
+ { loader: "bepinex-5", files: ["BepInEx/core/BepInEx.dll"] },
137
+ ],
138
+ r2modmanFolder: "DysonSphereProgram",
139
+ },
140
+ {
141
+ gameId: "boneworks",
142
+ steamAppId: "823500",
143
+ displayName: "BONEWORKS",
144
+ family: "unity-coop",
145
+ loaderChecks: [
146
+ { loader: "melonloader", files: ["MelonLoader/MelonLoader.dll"] },
147
+ ],
148
+ r2modmanFolder: "BONEWORKS",
149
+ },
150
+ {
151
+ gameId: "thesims4",
152
+ steamAppId: "1222670",
153
+ displayName: "The Sims 4",
154
+ family: "sims",
155
+ // The Sims 4 has no loader — mods drop into Documents/Electronic Arts/...
156
+ loaderChecks: [],
157
+ },
158
+ ];
159
+ //# sourceMappingURL=games.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"games.js","sourceRoot":"","sources":["../../src/detect/games.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { GameDef, ModLoader } from "./games.js";
2
+ /**
3
+ * Identify the mod loader installed for a given game by file presence. First
4
+ * match wins — KNOWN_GAMES orders the checks so the most specific loader is
5
+ * tried first (e.g. IL2CPP BepInEx before Mono BepInEx for the same game).
6
+ *
7
+ * Returns "none" if no loader signature is found. That's still a useful
8
+ * answer — it tells the LLM the user's setup is vanilla, which changes how
9
+ * crash diagnosis should proceed.
10
+ */
11
+ export declare function detectModLoader(installDir: string, game: GameDef): ModLoader;
12
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/detect/loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,SAAS,CAQ5E"}
@@ -0,0 +1,20 @@
1
+ import { join } from "node:path";
2
+ import { pathExists } from "./os.js";
3
+ /**
4
+ * Identify the mod loader installed for a given game by file presence. First
5
+ * match wins — KNOWN_GAMES orders the checks so the most specific loader is
6
+ * tried first (e.g. IL2CPP BepInEx before Mono BepInEx for the same game).
7
+ *
8
+ * Returns "none" if no loader signature is found. That's still a useful
9
+ * answer — it tells the LLM the user's setup is vanilla, which changes how
10
+ * crash diagnosis should proceed.
11
+ */
12
+ export function detectModLoader(installDir, game) {
13
+ for (const check of game.loaderChecks) {
14
+ const allPresent = check.files.every((rel) => pathExists(join(installDir, rel)));
15
+ if (allPresent)
16
+ return check.loader;
17
+ }
18
+ return "none";
19
+ }
20
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/detect/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGrC;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkB,EAAE,IAAa;IAC/D,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACtC,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAC3C,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAClC,CAAC;QACF,IAAI,UAAU;YAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IACtC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { GameDef } from "./games.js";
2
+ export type ManagerName = "vortex" | "mo2" | "r2modman" | "thunderstore-mm" | "curseforge";
3
+ export type DetectedManager = {
4
+ name: ManagerName;
5
+ /** Where the manager's state lives on disk. Useful for downstream tools. */
6
+ dataPath: string;
7
+ /** Game IDs this manager is known to manage on this machine (best-effort). */
8
+ managedGameIds?: string[];
9
+ };
10
+ /**
11
+ * Detect every mod manager whose state directory is present on this system.
12
+ * Each manager is reported once, with the data path the workbench should read
13
+ * if it ever needs to interrogate state (load order, profiles, etc.).
14
+ *
15
+ * Note: presence ≠ active. A user may have Vortex installed but use MO2 daily.
16
+ * Per-game inference (inferManagerForGame) makes the best guess we can.
17
+ */
18
+ export declare function detectInstalledManagers(): DetectedManager[];
19
+ /**
20
+ * Heuristic guess at which detected manager is most likely managing a given
21
+ * game. Family-based: bethesda games skew Vortex/MO2, unity-coop skews
22
+ * r2modman, sims/minecraft skews CurseForge. Returns null if no detected
23
+ * manager fits the game.
24
+ */
25
+ export declare function inferManagerForGame(game: GameDef, managers: DetectedManager[]): ManagerName | null;
26
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/detect/manager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,KAAK,GACL,UAAU,GACV,iBAAiB,GACjB,YAAY,CAAC;AAEjB,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AA2EF;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,IAAI,eAAe,EAAE,CA6C3D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,eAAe,EAAE,GAC1B,WAAW,GAAG,IAAI,CA4BpB"}