omp-wechat 1.6.0 → 1.7.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.
Files changed (2) hide show
  1. package/dist/index.js +73 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2006,13 +2006,20 @@ import { homedir as homedir6 } from "os";
2006
2006
  import { existsSync as existsSync2, mkdirSync as mkdirSync5, readdirSync as readdirSync2, statSync as statSync3, rmSync } from "fs";
2007
2007
  var STATE_DIR4 = join7(homedir6(), ".omp-wechat");
2008
2008
  var SESSIONS_DIR = join7(STATE_DIR4, "sessions");
2009
+ var DEFAULT_OUTBOX_BASE = join7(STATE_DIR4, "outbox");
2009
2010
  var STALE_THRESHOLD_MS = 30 * 24 * 60 * 60 * 1000;
2010
2011
  function sanitizeChatId(chatId) {
2011
2012
  return chatId.replace(/[^a-zA-Z0-9_@.-]/g, "_").slice(0, 200);
2012
2013
  }
2014
+ function sanitizeOutboxChatId(chatId) {
2015
+ return chatId.replace(/[^a-zA-Z0-9_-]/g, "_");
2016
+ }
2013
2017
  function sessionDirFor(chatId) {
2014
2018
  return join7(SESSIONS_DIR, sanitizeChatId(chatId));
2015
2019
  }
2020
+ function outboxDirFor(chatId, outboxBase) {
2021
+ return join7(outboxBase ?? DEFAULT_OUTBOX_BASE, sanitizeOutboxChatId(chatId));
2022
+ }
2016
2023
  function ensureSessionsDir() {
2017
2024
  mkdirSync5(SESSIONS_DIR, { recursive: true, mode: 448 });
2018
2025
  }
@@ -2028,6 +2035,54 @@ function removeSessionDir(chatId) {
2028
2035
  return false;
2029
2036
  }
2030
2037
  }
2038
+ function removeOutboxDir(chatId, outboxBase) {
2039
+ const dir = outboxDirFor(chatId, outboxBase);
2040
+ if (!existsSync2(dir))
2041
+ return false;
2042
+ try {
2043
+ rmSync(dir, { recursive: true, force: true });
2044
+ logger.info(`Removed outbox dir: ${dir}`);
2045
+ return true;
2046
+ } catch (err) {
2047
+ logger.warn(`Failed to remove outbox dir ${dir}: ${err}`);
2048
+ return false;
2049
+ }
2050
+ }
2051
+ function cleanupStaleOutboxes(outboxBase) {
2052
+ const base = outboxBase ?? DEFAULT_OUTBOX_BASE;
2053
+ if (!existsSync2(base))
2054
+ return 0;
2055
+ const now = Date.now();
2056
+ let removed = 0;
2057
+ for (const entry of readdirSync2(base, { withFileTypes: true })) {
2058
+ if (!entry.isDirectory())
2059
+ continue;
2060
+ const dir = join7(base, entry.name);
2061
+ let newestMtime = 0;
2062
+ try {
2063
+ for (const file of readdirSync2(dir)) {
2064
+ const mtime = statSync3(join7(dir, file)).mtimeMs;
2065
+ if (mtime > newestMtime)
2066
+ newestMtime = mtime;
2067
+ }
2068
+ } catch {
2069
+ continue;
2070
+ }
2071
+ if (newestMtime === 0 || now - newestMtime > STALE_THRESHOLD_MS) {
2072
+ try {
2073
+ rmSync(dir, { recursive: true, force: true });
2074
+ removed++;
2075
+ logger.info(`Cleaned up stale outbox dir: ${entry.name}`);
2076
+ } catch (err) {
2077
+ logger.warn(`Failed to cleanup outbox dir ${entry.name}: ${err}`);
2078
+ }
2079
+ }
2080
+ }
2081
+ if (removed > 0) {
2082
+ logger.info(`Outbox cleanup: removed ${removed} stale outbox(es)`);
2083
+ }
2084
+ return removed;
2085
+ }
2031
2086
  function cleanupStaleSessions() {
2032
2087
  if (!existsSync2(SESSIONS_DIR))
2033
2088
  return 0;
@@ -2081,15 +2136,7 @@ function clearAllSessions() {
2081
2136
 
2082
2137
  // src/engine/session.ts
2083
2138
  import { mkdirSync as mkdirSync6, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
2084
- import { homedir as homedir7 } from "os";
2085
2139
  import { join as join8 } from "path";
2086
- var DEFAULT_OUTBOX_BASE = join8(homedir7(), ".omp-wechat", "outbox");
2087
- function sanitizeChatId2(chatId) {
2088
- return chatId.replace(/[^a-zA-Z0-9_-]/g, "_");
2089
- }
2090
- function outboxDirFor(chatId, config) {
2091
- return join8(config.outboxDir ?? DEFAULT_OUTBOX_BASE, sanitizeChatId2(chatId));
2092
- }
2093
2140
  function outboxInstructions(outboxDir) {
2094
2141
  return `## File delivery to WeChat
2095
2142
 
@@ -2137,7 +2184,7 @@ class ChatSession {
2137
2184
  }
2138
2185
  static async create(chatId, contextToken, config, onReply, onFiles) {
2139
2186
  logger.info(`Creating session: ${chatId}`);
2140
- const outboxDir = outboxDirFor(chatId, config);
2187
+ const outboxDir = outboxDirFor(chatId, config.outboxDir);
2141
2188
  const sendFilesEnabled = config.sendFiles !== false;
2142
2189
  if (sendFilesEnabled) {
2143
2190
  try {
@@ -2270,13 +2317,14 @@ class SessionPool {
2270
2317
  get(chatId) {
2271
2318
  return this.pool.get(chatId);
2272
2319
  }
2273
- async resetSession(chatId) {
2320
+ async resetSession(chatId, config) {
2274
2321
  const entry = this.pool.get(chatId);
2275
2322
  if (entry) {
2276
2323
  await entry.dispose();
2277
2324
  this.pool.delete(chatId);
2278
2325
  }
2279
2326
  removeSessionDir(chatId);
2327
+ removeOutboxDir(chatId, config.outboxDir);
2280
2328
  }
2281
2329
  getContextToken(chatId) {
2282
2330
  return this.pool.get(chatId)?.getContextToken() ?? "";
@@ -2479,7 +2527,7 @@ class ModelCommand {
2479
2527
  // src/command/new-session-command.ts
2480
2528
  class NewSessionInvocation {
2481
2529
  async execute(ctx) {
2482
- await ctx.pool.resetSession(ctx.chatId);
2530
+ await ctx.pool.resetSession(ctx.chatId, ctx.config);
2483
2531
  return "Session reset. Your next message starts a fresh conversation.";
2484
2532
  }
2485
2533
  }
@@ -2583,7 +2631,11 @@ class WeChatBridge {
2583
2631
  this.releaseLock();
2584
2632
  });
2585
2633
  cleanupStaleSessions();
2586
- this.cleanupTimer = setInterval(() => cleanupStaleSessions(), 6 * 60 * 60 * 1000);
2634
+ cleanupStaleOutboxes(config.outboxDir);
2635
+ this.cleanupTimer = setInterval(() => {
2636
+ cleanupStaleSessions();
2637
+ cleanupStaleOutboxes(config.outboxDir);
2638
+ }, 6 * 60 * 60 * 1000);
2587
2639
  return this.state;
2588
2640
  }
2589
2641
  async stop() {
@@ -2835,7 +2887,7 @@ ${truncated}
2835
2887
  }
2836
2888
 
2837
2889
  // src/service.ts
2838
- import { platform, homedir as homedir8 } from "os";
2890
+ import { platform, homedir as homedir7 } from "os";
2839
2891
  import { join as join9, basename as basename4 } from "path";
2840
2892
  import { existsSync as existsSync3, mkdirSync as mkdirSync7, writeFileSync as writeFileSync4, rmSync as rmSync3 } from "fs";
2841
2893
  var PLIST_LABEL = "com.omp-wechat";
@@ -2851,14 +2903,14 @@ function detectPlatform() {
2851
2903
  return "other";
2852
2904
  }
2853
2905
  function getLogDir() {
2854
- return join9(homedir8(), ".omp", "logs");
2906
+ return join9(homedir7(), ".omp", "logs");
2855
2907
  }
2856
2908
  function resolveHostBinary() {
2857
2909
  const exe = process.execPath || "omp";
2858
2910
  return basename4(exe);
2859
2911
  }
2860
2912
  function plistPath() {
2861
- return join9(homedir8(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
2913
+ return join9(homedir7(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
2862
2914
  }
2863
2915
  function generatePlist() {
2864
2916
  const omp = resolveHostBinary();
@@ -2894,14 +2946,14 @@ function generatePlist() {
2894
2946
  <key>PATH</key>
2895
2947
  <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
2896
2948
  <key>HOME</key>
2897
- <string>${homedir8()}</string>
2949
+ <string>${homedir7()}</string>
2898
2950
  </dict>
2899
2951
  </dict>
2900
2952
  </plist>
2901
2953
  `;
2902
2954
  }
2903
2955
  function installLaunchd() {
2904
- const dir = join9(homedir8(), "Library", "LaunchAgents");
2956
+ const dir = join9(homedir7(), "Library", "LaunchAgents");
2905
2957
  mkdirSync7(dir, { recursive: true });
2906
2958
  mkdirSync7(getLogDir(), { recursive: true });
2907
2959
  const plist = plistPath();
@@ -2943,7 +2995,7 @@ ExecStart=/bin/sh -c 'while true; do echo "{\\"id\\":\\"ka\\",\\"type\\":\\"get_
2943
2995
  Restart=always
2944
2996
  RestartSec=10
2945
2997
 
2946
- Environment=HOME=${homedir8()}
2998
+ Environment=HOME=${homedir7()}
2947
2999
  Environment=PATH=/usr/local/bin:/usr/bin:/bin
2948
3000
 
2949
3001
  StandardOutput=null
@@ -2952,7 +3004,7 @@ StandardError=append:${logDir}/rpc.log
2952
3004
  NoNewPrivileges=true
2953
3005
  ProtectSystem=strict
2954
3006
  ProtectHome=read-only
2955
- ReadWritePaths=${logDir} ${join9(homedir8(), ".omp-wechat")} ${join9(homedir8(), ".omp")}
3007
+ ReadWritePaths=${logDir} ${join9(homedir7(), ".omp-wechat")} ${join9(homedir7(), ".omp")}
2956
3008
  PrivateTmp=true
2957
3009
 
2958
3010
  [Install]
@@ -2993,7 +3045,7 @@ function uninstallSystemd() {
2993
3045
  }
2994
3046
  var WIN_TASK_NAME = "OMP-Wechat";
2995
3047
  function winScriptPath() {
2996
- return join9(homedir8(), ".omp-wechat", "omp-wechat-rpc.ps1");
3048
+ return join9(homedir7(), ".omp-wechat", "omp-wechat-rpc.ps1");
2997
3049
  }
2998
3050
  function generateWinScript() {
2999
3051
  const omp = process.execPath || "omp";
@@ -3036,7 +3088,7 @@ while ($true) {
3036
3088
  `;
3037
3089
  }
3038
3090
  function installWinTask() {
3039
- mkdirSync7(join9(homedir8(), ".omp-wechat"), { recursive: true });
3091
+ mkdirSync7(join9(homedir7(), ".omp-wechat"), { recursive: true });
3040
3092
  mkdirSync7(getLogDir(), { recursive: true });
3041
3093
  writeFileSync4(winScriptPath(), generateWinScript());
3042
3094
  Bun.spawnSync(["schtasks", "/end", "/tn", WIN_TASK_NAME], { stderr: "ignore" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omp-wechat",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "OMP/Pi extension: bridge WeChat messages to OMP's AI engine via the iLink Bot API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",