tavern-harness 0.1.11 → 0.1.12

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/README.md CHANGED
@@ -10,6 +10,10 @@
10
10
  <a href="https://www.npmjs.com/package/tavern-harness"><img alt="npm" src="https://img.shields.io/npm/v/tavern-harness?style=flat-square" /></a>
11
11
  </p>
12
12
 
13
+ <p align="center">
14
+ <strong>English</strong> | <a href="README.zh.md">简体中文</a>
15
+ </p>
16
+
13
17
  # Tavern Harness · An AI-Native Role-Playing Sandbox
14
18
 
15
19
  <a id="demo"></a>
@@ -74,9 +78,9 @@ After starting the app, open **Settings → Model Service Provider**:
74
78
  2. **Test the connection**: the app fetches the model list automatically. If the target service does not expose CORS headers, requests are forwarded through the built-in same-origin proxy for private-network or LAN addresses. On success, the Base URL is rewritten to its proxy form and saved.
75
79
  3. **Select a model**: click the model name at the top of the chat page, then return to the conversation and start chatting.
76
80
 
77
- ### Import a Game and Start Playing
81
+ ### Import a Gameplay and Start Playing
78
82
 
79
- Download the game file below. Click **Import** in the upper-left corner, then import the file you downloaded to create a complete game environment—including characters, lorebooks, skills, and more—and start playing right away:
83
+ Download the gameplay file below. Click **Import** in the upper-left corner, then import the file you downloaded to create a complete game environment—including characters, lorebooks, skills, and more—and start playing right away:
80
84
 
81
85
  [th-demo-affinity-gameplay-en.json](./docs/assets/gameplay/th-demo-affinity-gameplay-en.json)
82
86
 
package/README.zh.md CHANGED
@@ -10,6 +10,10 @@
10
10
  <a href="https://www.npmjs.com/package/tavern-harness"><img alt="npm" src="https://img.shields.io/npm/v/tavern-harness?style=flat-square" /></a>
11
11
  </p>
12
12
 
13
+ <p align="center">
14
+ <a href="README.md">English</a> | <strong>简体中文</strong>
15
+ </p>
16
+
13
17
  # Tavern Harness · AI 原生的角色扮演沙盒
14
18
 
15
19
  <a id="demo"></a>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tavern-harness",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Tavern Harness — 酒馆模式下的本地 AI Agent 助手(MyAgent-Android 的 Web 复刻)",
5
5
  "private": false,
6
6
  "type": "module",
package/src/core/proxy.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  // 自动回退到 Vite 开发服务器的同源代理。
4
4
  // 代理规则:http://<当前站点>/api/<host:port>/<剩余路径>
5
5
  // 例:http://192.168.1.5:8788/v1/ → http://localhost:5173/api/192.168.1.5:8788/v1/
6
+ // https://api.example.com/v1/ → http://localhost:5173/api/https/api.example.com/v1/
6
7
  // ============================================================
7
8
 
8
9
  /** 判断当前环境是否可能提供代理(Vite dev 服务器) */
@@ -29,7 +30,7 @@ export function isProxyUrl(url: string): boolean {
29
30
  * 例:
30
31
  * http://192.168.1.5:8788 → http://localhost:5173/api/192.168.1.5:8788
31
32
  * http://192.168.1.5:8788/v1/ → http://localhost:5173/api/192.168.1.5:8788/v1/
32
- * https://api.deepseek.com/v1/ → null(公有 HTTPS 服务一般带 CORS;不代理外网)
33
+ * https://api.deepseek.com/v1/ → http://localhost:5173/api/https/api.deepseek.com/v1/
33
34
  */
34
35
  export function toProxyUrl(baseUrl: string): string | null {
35
36
  if (!canUseProxy() || isProxyUrl(baseUrl)) return null;
@@ -39,15 +40,15 @@ export function toProxyUrl(baseUrl: string): string | null {
39
40
  } catch {
40
41
  return null;
41
42
  }
42
- if (u.protocol !== 'http:' && u.protocol !== 'https:') return null;
43
- // 仅代理内网/局域网地址,外网公开 API 保持直连(避免滥用代理)
44
- const ipv4 = /^\d{1,3}(\.\d{1,3}){3}$/.test(u.hostname);
45
- const isPrivateHost = ipv4 || u.hostname === 'localhost' || u.hostname === '127.0.0.1';
46
- if (!isPrivateHost) return null;
43
+
44
+ const isLocalHost = u.hostname === 'localhost' || u.hostname === '127.0.0.1';
45
+ const isIpv4 = /^\d{1,3}(\.\d{1,3}){3}$/.test(u.hostname);
46
+ if (u.protocol !== 'https:' && !isLocalHost && !isIpv4) return null;
47
47
 
48
48
  const host = u.host; // hostname:port
49
49
  const rest = u.pathname.replace(/^\/+/, '');
50
- const path = `/api/${host}/${rest}`.replace(/\/+$/, '');
50
+ const protocol = u.protocol === 'https:' ? 'https/' : '';
51
+ const path = `/api/${protocol}${host}/${rest}`.replace(/\/+$/, '');
51
52
  return `${window.location.origin}${path}`;
52
53
  }
53
54
 
package/vite.config.ts CHANGED
@@ -13,9 +13,11 @@ import type { IncomingMessage, ServerResponse } from 'node:http';
13
13
  const projectRoot = dirname(fileURLToPath(import.meta.url));
14
14
 
15
15
  /**
16
- * CORS 转发中间件:为本地(无 CORS 头)的 OpenAI 兼容服务提供同源代理。
16
+ * CORS 转发中间件:为本地及外部 HTTPS OpenAI 兼容服务提供同源代理。
17
17
  * Base URL 填 http://localhost:5173/api/192.168.50.175:8788/ 即可;
18
- * /api/<host>/ 之后的路径(含 query)原样转发到 http://<host>/。
18
+ * HTTPS 目标格式为 /api/https/<host>/,例如:
19
+ * http://localhost:5173/api/https/ark.cn-beijing.volces.com/api/v3。
20
+ * /api/<host>/ 之后的路径(含 query)原样转发到目标服务。
19
21
  */
20
22
  function corsProxyPlugin(): Plugin {
21
23
  return {
@@ -26,10 +28,13 @@ function corsProxyPlugin(): Plugin {
26
28
  const m = /^\/api\/([^/]+)(\/[^?]*)?(\?.*)?$/.exec(url);
27
29
  if (!m) return next();
28
30
 
29
- const rawHost = m[1]; // e.g. 192.168.50.175:8788
31
+ const rawHost = m[1]; // e.g. 192.168.50.175:8788 or https
30
32
  const path = (m[2] || '') + (m[3] || '');
31
- const isHttps = rawHost.startsWith('https://');
32
- const host = rawHost.replace(/^https?:\/\//, '');
33
+ const isHttps = rawHost === 'https';
34
+ const host = isHttps ? (m[2] || '').split('/')[1] : rawHost;
35
+ const forwardedPath = isHttps
36
+ ? `/${(m[2] || '').split('/').slice(2).join('/')}${m[3] || ''}`
37
+ : path;
33
38
  const [hostname, portStr] = host.split(':');
34
39
  const port = portStr ? parseInt(portStr, 10) : isHttps ? 443 : 80;
35
40
 
@@ -44,7 +49,7 @@ function corsProxyPlugin(): Plugin {
44
49
  protocol: isHttps ? 'https:' : 'http:',
45
50
  hostname,
46
51
  port,
47
- path,
52
+ path: forwardedPath,
48
53
  method: req.method,
49
54
  headers: forwardedHeaders,
50
55
  },