@myassis/gateway 1.0.20 → 1.0.22

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.
@@ -34,6 +34,9 @@ const fs = __importStar(require("fs"));
34
34
  * dist/config/index.js → 上三级 = 包根目录
35
35
  */
36
36
  function getPackageRootDir() {
37
+ if (process.pkg) {
38
+ return path.dirname(process.execPath);
39
+ }
37
40
  return path.resolve(__dirname, '..', '..');
38
41
  }
39
42
  const getEnvPath = () => {
@@ -42,7 +45,16 @@ const getEnvPath = () => {
42
45
  if (fs.existsSync(cwdEnvPath)) {
43
46
  return cwdEnvPath;
44
47
  }
45
- // 2. 包安装目录(随包发布的默认 .env
48
+ // 2. pkg 环境:从 snapshot 虚拟路径读取打包的 .env
49
+ if (process.pkg) {
50
+ // __dirname 在 pkg 中指向 /snapshot/pocketclaw/gateway/dist/config
51
+ // 打包的 .env 在 /snapshot/pocketclaw/gateway/dist/.env
52
+ const snapshotEnvPath = path.resolve(__dirname, '..', '.env');
53
+ if (fs.existsSync(snapshotEnvPath)) {
54
+ return snapshotEnvPath;
55
+ }
56
+ }
57
+ // 3. 包安装目录(随包发布的默认 .env)
46
58
  const pkgEnvPath = path.join(getPackageRootDir(), 'dist', '.env');
47
59
  if (fs.existsSync(pkgEnvPath)) {
48
60
  return pkgEnvPath;
@@ -433,8 +433,8 @@ router.post('/sessions/:sessionId/stream', ensureAgentManager, async (req, res)
433
433
  const userId = req.userId;
434
434
  const { sessionId } = req.params;
435
435
  const { content, attachments, userMessageId, assistantMessageId } = req.body;
436
- if (!content) {
437
- return res.status(400).json({ success: false, error: 'Content is required' });
436
+ if (!content && attachments.length === 0) {
437
+ return res.status(400).json({ success: false, error: 'Content or attachments are required' });
438
438
  }
439
439
  // Find session directly
440
440
  const session = (0, index_js_2.getSessionManager)(userId).getSession(sessionId);
@@ -400,7 +400,7 @@ class LLMClient {
400
400
  }
401
401
  const tokens = JSON.stringify(body).length;
402
402
  logger.debug('tokens', tokens);
403
- if (tokens > 200000) {
403
+ if (tokens > 200000 && !existAttachments) {
404
404
  logger.warn('message is too large and has writen to the file debug.json');
405
405
  await promises_1.default.writeFile('debug.json', JSON.stringify(body.messages), 'utf-8');
406
406
  throw Error('exceed max message tokens');
@@ -110,8 +110,22 @@ class Session {
110
110
  // 将附件统一为 Attachment 对象格式
111
111
  const normalizedAttachments = (attachments || []).map((att) => {
112
112
  if (typeof att === 'string') {
113
- // URL 字符串格式,转换为对象
113
+ // 可能是 base64 data URL 或普通 URL
114
114
  const url = att;
115
+ const mimeMatch = url.match(/^data:([^;]+)/);
116
+ if (mimeMatch) {
117
+ // base64 data URL: 从 MIME 识别类型
118
+ const mime = mimeMatch[1];
119
+ let type = 'file';
120
+ if (mime.startsWith('image/'))
121
+ type = 'image';
122
+ else if (mime.startsWith('video/'))
123
+ type = 'video';
124
+ else if (mime.startsWith('audio/'))
125
+ type = 'audio';
126
+ return { type, name: 'attachment', url };
127
+ }
128
+ // 普通 URL: 从后缀识别类型
115
129
  const name = url.split('/').pop().split('?')[0] || 'attachment';
116
130
  const ext = name.split('.').pop()?.toLowerCase() || '';
117
131
  const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'svg'];
@@ -127,10 +141,22 @@ class Session {
127
141
  return { type, name, url };
128
142
  }
129
143
  // 已经是对象格式,确保有必要字段
144
+ const url = att.url || att.uri || '';
145
+ const mimeMatch = url.match(/^data:([^;]+)/);
146
+ let type = att.type || 'file';
147
+ if (!att.type && mimeMatch) {
148
+ const mime = mimeMatch[1];
149
+ if (mime.startsWith('image/'))
150
+ type = 'image';
151
+ else if (mime.startsWith('video/'))
152
+ type = 'video';
153
+ else if (mime.startsWith('audio/'))
154
+ type = 'audio';
155
+ }
130
156
  return {
131
- type: att.type || 'file',
157
+ type,
132
158
  name: att.name || 'attachment',
133
- url: att.url || att.uri || '',
159
+ url,
134
160
  size: att.size,
135
161
  mimeType: att.mimeType,
136
162
  };
@@ -15,6 +15,12 @@ const logger = (0, shared_1.getLogger)('SessionStore');
15
15
  * 用 __dirname 定位,比 process.execPath 可靠
16
16
  */
17
17
  function getPackageRootDir() {
18
+ // pkg 打包后 __dirname 是 /snapshot/... 虚拟路径,无法写文件
19
+ // 用 process.pkg 判断是否在 pkg 环境中
20
+ if (process.pkg) {
21
+ // process.execPath 指向二进制文件本身,取其所在目录
22
+ return path_1.default.dirname(process.execPath);
23
+ }
18
24
  // dist/services/session/SessionStore.js → 包根目录
19
25
  return path_1.default.resolve(__dirname, '..', '..', '..');
20
26
  }
@@ -33,6 +39,13 @@ function getDbPath() {
33
39
  }
34
40
  exports.getDbPath = getDbPath;
35
41
  function getMigrationsDir() {
42
+ // pkg 环境:从 snapshot 虚拟路径读取打包的 migrations
43
+ if (process.pkg) {
44
+ const snapshotMigrations = path_1.default.resolve(__dirname, '..', '..', '..', 'migrations');
45
+ if (fs_1.default.existsSync(snapshotMigrations)) {
46
+ return snapshotMigrations;
47
+ }
48
+ }
36
49
  // migrations 随包发布,从包安装目录读取
37
50
  const pkgMigrations = path_1.default.join(getPackageRootDir(), 'migrations');
38
51
  if (fs_1.default.existsSync(pkgMigrations)) {
@@ -22,13 +22,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
25
  Object.defineProperty(exports, "__esModule", { value: true });
29
26
  exports.searchTool = void 0;
30
27
  // @ts-ignore
31
- const got_1 = __importDefault(require("got"));
28
+ const undici_1 = require("undici");
32
29
  const cheerio = __importStar(require("cheerio"));
33
30
  exports.searchTool = {
34
31
  name: 'search',
@@ -44,14 +41,15 @@ exports.searchTool = {
44
41
  handler: async (args) => {
45
42
  try {
46
43
  const { query, limit = 5 } = args;
47
- const response = await (0, got_1.default)(`https://cn.bing.com/search?q=${encodeURIComponent(query)}`, {
44
+ const response = await (0, undici_1.fetch)(`https://cn.bing.com/search?q=${encodeURIComponent(query)}`, {
48
45
  headers: {
49
46
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
50
47
  'Accept-Language': 'zh-CN,zh;q=0.9',
51
48
  },
52
- timeout: { request: 10000 },
49
+ signal: AbortSignal.timeout(10000),
53
50
  });
54
- const $ = cheerio.load(response.body);
51
+ const body = await response.text();
52
+ const $ = cheerio.load(body);
55
53
  const results = [];
56
54
  $('li.b_algo').each((_, el) => {
57
55
  if (results.length >= limit)
@@ -22,13 +22,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
25
  Object.defineProperty(exports, "__esModule", { value: true });
29
26
  exports.webFetchTool = void 0;
30
27
  // @ts-ignore
31
- const got_1 = __importDefault(require("got"));
28
+ const undici_1 = require("undici");
32
29
  const cheerio = __importStar(require("cheerio"));
33
30
  exports.webFetchTool = {
34
31
  name: 'webFetch',
@@ -44,13 +41,14 @@ exports.webFetchTool = {
44
41
  handler: async (args) => {
45
42
  try {
46
43
  const { url, query } = args;
47
- const response = await (0, got_1.default)(url, {
44
+ const response = await (0, undici_1.fetch)(url, {
48
45
  headers: {
49
46
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
50
47
  },
51
- timeout: { request: 15000 },
48
+ signal: AbortSignal.timeout(15000),
52
49
  });
53
- const $ = cheerio.load(response.body);
50
+ const body = await response.text();
51
+ const $ = cheerio.load(body);
54
52
  let content = $.html();
55
53
  if (query) {
56
54
  content = $(query).text().trim() || `选择器 ${query} 未找到匹配内容`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myassis/gateway",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "我的助手 Gateway Service - 本地 AI 网关服务,支持认证、WebSocket 实时通信和任务调度",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -24,9 +24,10 @@
24
24
  "start": "node dist/index.js",
25
25
  "build": "tsc --skipLibCheck",
26
26
  "postbuild": "node scripts/add-shebang.js && npx tsc-alias",
27
- "pkg:win": "npx @yao-pkg/pkg . --targets node18-win-x64 --output myassis-gateway-win.exe",
28
- "pkg:linux": "npx @yao-pkg/pkg . --targets node18-linux-x64 --output myassis-gateway-linux",
27
+ "pkg:win": "node scripts/pkg-build-win.js node24-win-x64 myassis-gateway-win.exe",
28
+ "pkg:linux": "npx @yao-pkg/pkg . --targets node24-linux-x64 --output myassis-gateway-linux",
29
29
  "pkg:all": "npm run pkg:win && npm run pkg:linux",
30
+ "pkg:linux-analyze": "npx @yao-pkg/pkg . --targets node24-linux-x64 --output myassis-gateway-linux --public-packages got --debug",
30
31
  "test": "jest"
31
32
  },
32
33
  "keywords": [
@@ -39,17 +40,16 @@
39
40
  ],
40
41
  "author": "duzhengjie",
41
42
  "dependencies": {
42
- "@myassis/shared": "1.0.15",
43
+ "@myassis/shared": "workspace:*",
43
44
  "@nut-tree/nut-js": "^4.2.0",
44
45
  "axios": "^1.15.2",
45
46
  "bcryptjs": "^2.4.3",
46
- "better-sqlite3": "^8.7.0",
47
+ "better-sqlite3": "^11.10.0",
47
48
  "cheerio": "^1.2.0",
48
49
  "compression": "^1.7.4",
49
50
  "cors": "^2.8.5",
50
51
  "dotenv": "^16.3.1",
51
52
  "express": "^4.18.2",
52
- "got": "^15.0.3",
53
53
  "helmet": "^7.1.0",
54
54
  "https-proxy-agent": "^9.0.0",
55
55
  "jsonwebtoken": "^9.0.2",
@@ -61,7 +61,6 @@
61
61
  },
62
62
  "devDependencies": {
63
63
  "@types/bcryptjs": "^2.4.6",
64
- "@types/compression": "^1.7.5",
65
64
  "@types/cors": "^2.8.17",
66
65
  "@types/express": "^4.17.21",
67
66
  "@types/jsonwebtoken": "^9.0.6",
@@ -72,7 +71,8 @@
72
71
  "@yao-pkg/pkg": "^6.20.0",
73
72
  "tsc-alias": "^1.8.10",
74
73
  "tsx": "^4.7.0",
75
- "typescript": "^5.3.3"
74
+ "typescript": "^5.3.3",
75
+ "@yao-pkg/pkg-fetch": "3.6.3"
76
76
  },
77
77
  "pkg": {
78
78
  "scripts": [
@@ -81,11 +81,14 @@
81
81
  "assets": [
82
82
  "dist/**/*",
83
83
  "migrations/**/*",
84
- "README*"
84
+ "README*",
85
+ "node_modules/better-sqlite3/build/Release/better_sqlite3.node",
86
+ "node_modules/.pnpm/@nut-tree+libnut-linux@2.7.1/node_modules/@nut-tree/libnut-linux/build/Release/libnut.node",
87
+ "node_modules/.pnpm/@nut-tree+libnut-win32@2.7.1/node_modules/@nut-tree/libnut-win32/build/Release/libnut.node"
85
88
  ],
86
89
  "targets": [
87
- "node18-win-x64",
88
- "node18-linux-x64"
90
+ "node24-win-x64",
91
+ "node24-linux-x64"
89
92
  ]
90
93
  }
91
94
  }
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ // pkg-build-win.js - Windows pkg build using PKG_CACHE_PATH
3
+ // Points to ~/.pkg-cache which contains the correct v3.6 patched binary (40.6 MB, hash matches)
4
+ 'use strict';
5
+ const { spawn } = require('child_process');
6
+ const path = require('path');
7
+ const os = require('os');
8
+ const fs = require('fs');
9
+
10
+ const TARGET = process.argv[2] || 'node18-win-x64';
11
+ const OUTPUT = process.argv[3] || 'myassis-gateway-win.exe';
12
+
13
+ const CACHE_DIR = path.join(os.homedir(), '.pkg-cache');
14
+ const V36_BINARY = path.join(CACHE_DIR, 'v3.6', 'fetched-v18.20.8-win-x64');
15
+ const PKG_BIN = path.resolve(__dirname, '../node_modules/@yao-pkg/pkg/lib-es5/bin.js');
16
+
17
+ function log(msg) { console.error('[pkg-build] ' + msg); }
18
+
19
+ async function main() {
20
+ log(`Building for ${TARGET}`);
21
+ log(`Output: ${OUTPUT}`);
22
+
23
+ // Verify v3.6 binary exists
24
+ if (!fs.existsSync(V36_BINARY)) {
25
+ log(`ERROR: Patched binary not found at ${V36_BINARY}`);
26
+ log('Please run: node node_modules/@yao-pkg/pkg/lib-es5/bin.js --targets node18-win-x64 first');
27
+ process.exit(1);
28
+ }
29
+ const size = (fs.statSync(V36_BINARY).size / 1024 / 1024).toFixed(1);
30
+ log(`Using patched binary: ${V36_BINARY} (${size} MB)`);
31
+
32
+ // Use PKG_CACHE_PATH so pkg-fetch finds the correct v3.6 binary by hash
33
+ const env = { ...process.env };
34
+ delete env.PKG_NODE_PATH; // MUST NOT use PKG_NODE_PATH - it bypasses placeholders check
35
+ env.PKG_CACHE_PATH = CACHE_DIR;
36
+ log(`PKG_CACHE_PATH=${CACHE_DIR}`);
37
+
38
+ log('Starting pkg...');
39
+ return new Promise((resolve) => {
40
+ const child = spawn(process.execPath, [PKG_BIN, '.', '--targets', TARGET, '--output', OUTPUT], {
41
+ cwd: path.resolve(__dirname, '..'),
42
+ env,
43
+ stdio: 'inherit'
44
+ });
45
+ child.on('exit', (code) => process.exit(code || 0));
46
+ child.on('error', (e) => { log('Spawn error: ' + e.message); process.exit(1); });
47
+ });
48
+ }
49
+
50
+ main().catch(e => { console.error('[pkg-build] Fatal:', e.message); process.exit(1); });