@co0ontty/wand 1.50.0 → 1.50.1-beta.g7c1c69b

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
@@ -168,7 +168,17 @@ src/
168
168
  session-logger.ts # 文件日志 ~/.wand/sessions/
169
169
  resume-policy.ts # Claude 历史绑定与恢复策略
170
170
  web-ui/ # 服务端渲染的前端 HTML/CSS/JS
171
- android/ # Android WebView 壳应用
171
+ android/ # Android 壳应用(submodule → co0ontty/wand-android)
172
+ macos/ # macOS 壳应用(submodule → co0ontty/wand-macos)
173
+ ios/ # iOS 壳应用(submodule → co0ontty/wand-ios)
174
+ ```
175
+
176
+ 三个客户端壳应用是独立仓库,以 git submodule 引用。克隆源码开发时需要带上:
177
+
178
+ ```bash
179
+ git clone --recurse-submodules https://github.com/co0ontty/wand.git
180
+ # 或已克隆后补拉:
181
+ git submodule update --init
172
182
  ```
173
183
 
174
184
  数据存储在 `~/.wand/` 下:`config.json`(配置)、`wand.db`(SQLite)、`sessions/`(日志)。
@@ -1,6 +1,6 @@
1
1
  {
2
- "commit": "e0af64185f64f37059e389f0a3380370359beaa7",
3
- "builtAt": "2026-06-10T11:02:02.091Z",
4
- "version": "1.50.0",
5
- "channel": "stable"
2
+ "commit": "7c1c69be6fa58b4a86b804288aff96dc2cecd675",
3
+ "builtAt": "2026-06-10T14:29:12.437Z",
4
+ "version": "1.50.1-beta.g7c1c69b",
5
+ "channel": "beta"
6
6
  }
package/dist/server.js CHANGED
@@ -91,30 +91,46 @@ const DISPLAY_VERSION = BUILD_INFO.version || PKG_VERSION;
91
91
  let cachedGitHubApk = null;
92
92
  let gitHubApkCacheTs = 0;
93
93
  const GITHUB_APK_CACHE_TTL = 10 * 60 * 1000; // 10 minutes
94
+ // 客户端代码没变时 CI 会跳过该平台的构建,最新 release 上可能没有 .apk/.dmg;
95
+ // 因此不能只查 /releases/latest,要按时间倒序遍历最近的 releases,取第一个带对应产物的。
96
+ async function fetchGitHubReleaseAssetByExt(ext) {
97
+ const apiUrl = PKG_REPO_URL.replace("github.com", "api.github.com/repos") + "/releases?per_page=30";
98
+ const resp = await fetch(apiUrl, {
99
+ headers: { "Accept": "application/vnd.github.v3+json", "User-Agent": "wand-server" },
100
+ signal: AbortSignal.timeout(10000),
101
+ });
102
+ if (!resp.ok)
103
+ return null;
104
+ const releases = await resp.json();
105
+ for (const release of releases) {
106
+ if (release.draft || release.prerelease)
107
+ continue;
108
+ const asset = release.assets.find(a => a.name.toLowerCase().endsWith(ext));
109
+ if (asset)
110
+ return { tagName: release.tag_name, body: release.body, asset };
111
+ }
112
+ return null;
113
+ }
94
114
  async function fetchGitHubLatestApk(forceRefresh = false) {
95
115
  const now = Date.now();
96
116
  if (!forceRefresh && cachedGitHubApk && (now - gitHubApkCacheTs < GITHUB_APK_CACHE_TTL)) {
97
117
  return cachedGitHubApk;
98
118
  }
99
119
  try {
100
- const apiUrl = PKG_REPO_URL.replace("github.com", "api.github.com/repos") + "/releases/latest";
101
- const resp = await fetch(apiUrl, {
102
- headers: { "Accept": "application/vnd.github.v3+json", "User-Agent": "wand-server" },
103
- signal: AbortSignal.timeout(10000),
104
- });
105
- if (!resp.ok)
106
- return cachedGitHubApk ?? null;
107
- const release = await resp.json();
108
- const apkAsset = release.assets.find(a => a.name.toLowerCase().endsWith(".apk"));
109
- if (!apkAsset)
120
+ const hit = await fetchGitHubReleaseAssetByExt(".apk");
121
+ if (!hit)
110
122
  return cachedGitHubApk ?? null;
111
- const version = extractAndroidApkVersion(release.tag_name) ?? release.tag_name.replace(/^v/, "");
123
+ // 版本号优先从文件名提取:未变化的平台沿用老包,挂它的 release tag 可能更新,
124
+ // 用 tag 当版本会让客户端「提示新版、下载到旧包」死循环。
125
+ const version = extractAndroidApkVersion(hit.asset.name)
126
+ ?? extractAndroidApkVersion(hit.tagName)
127
+ ?? hit.tagName.replace(/^v/, "");
112
128
  cachedGitHubApk = {
113
129
  version,
114
- downloadUrl: apkAsset.browser_download_url,
115
- fileName: apkAsset.name,
116
- size: apkAsset.size,
117
- releaseNotes: release.body ? release.body.trim().slice(0, 500) : undefined,
130
+ downloadUrl: hit.asset.browser_download_url,
131
+ fileName: hit.asset.name,
132
+ size: hit.asset.size,
133
+ releaseNotes: hit.body ? hit.body.trim().slice(0, 500) : undefined,
118
134
  };
119
135
  gitHubApkCacheTs = now;
120
136
  return cachedGitHubApk;
@@ -158,23 +174,18 @@ async function fetchGitHubLatestDmg(forceRefresh = false) {
158
174
  return cachedGitHubDmg;
159
175
  }
160
176
  try {
161
- const apiUrl = PKG_REPO_URL.replace("github.com", "api.github.com/repos") + "/releases/latest";
162
- const resp = await fetch(apiUrl, {
163
- headers: { "Accept": "application/vnd.github.v3+json", "User-Agent": "wand-server" },
164
- signal: AbortSignal.timeout(10000),
165
- });
166
- if (!resp.ok)
167
- return cachedGitHubDmg ?? null;
168
- const release = await resp.json();
169
- const dmgAsset = release.assets.find(a => a.name.toLowerCase().endsWith(".dmg"));
170
- if (!dmgAsset)
177
+ const hit = await fetchGitHubReleaseAssetByExt(".dmg");
178
+ if (!hit)
171
179
  return cachedGitHubDmg ?? null;
172
- const version = extractMacosDmgVersion(release.tag_name) ?? release.tag_name.replace(/^v/, "");
180
+ // APK:版本号优先从文件名提取,避免沿用老包时把 release tag 当成新版本。
181
+ const version = extractMacosDmgVersion(hit.asset.name)
182
+ ?? extractMacosDmgVersion(hit.tagName)
183
+ ?? hit.tagName.replace(/^v/, "");
173
184
  cachedGitHubDmg = {
174
185
  version,
175
- downloadUrl: dmgAsset.browser_download_url,
176
- fileName: dmgAsset.name,
177
- size: dmgAsset.size,
186
+ downloadUrl: hit.asset.browser_download_url,
187
+ fileName: hit.asset.name,
188
+ size: hit.asset.size,
178
189
  };
179
190
  gitHubDmgCacheTs = now;
180
191
  return cachedGitHubDmg;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@co0ontty/wand",
3
- "version": "1.50.0",
3
+ "version": "1.50.1-beta.g7c1c69b",
4
4
  "description": "A web terminal for local CLI tools like Claude.",
5
5
  "type": "module",
6
6
  "bin": {