@co0ontty/wand 4.44.0 → 4.45.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/build-info.json +3 -3
- package/dist/config.js +24 -0
- package/dist/distribution-manager.d.ts +3 -0
- package/dist/distribution-manager.js +46 -3
- package/dist/server-session-routes.js +10 -0
- package/dist/server-settings-routes.d.ts +1 -0
- package/dist/server-settings-routes.js +3 -1
- package/dist/server-update-routes.d.ts +3 -0
- package/dist/server-update-routes.js +17 -0
- package/dist/types.d.ts +6 -0
- package/dist/web-ui/content/scripts.js +70 -70
- package/dist/web-ui/embedded-assets.d.ts +1 -1
- package/dist/web-ui/embedded-assets.js +2 -2
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commit": "
|
|
3
|
-
"builtAt": "2026-08-
|
|
4
|
-
"version": "4.
|
|
2
|
+
"commit": "6788c46769838380333c0a8ff36fa192041ebae3",
|
|
3
|
+
"builtAt": "2026-08-22T04:51:22.312Z",
|
|
4
|
+
"version": "4.45.0",
|
|
5
5
|
"channel": "stable"
|
|
6
6
|
}
|
package/dist/config.js
CHANGED
|
@@ -70,6 +70,7 @@ export const defaultConfig = () => ({
|
|
|
70
70
|
language: "",
|
|
71
71
|
android: defaultAndroidApkConfig(),
|
|
72
72
|
macos: defaultMacosDmgConfig(),
|
|
73
|
+
ios: defaultIosIpaConfig(),
|
|
73
74
|
cardDefaults: defaultCardExpandDefaults(),
|
|
74
75
|
defaultModel: "",
|
|
75
76
|
defaultCodexModel: "",
|
|
@@ -594,6 +595,28 @@ function normalizeMacosDmgConfig(input) {
|
|
|
594
595
|
: defaults.currentDmgFile,
|
|
595
596
|
};
|
|
596
597
|
}
|
|
598
|
+
function defaultIosIpaConfig() {
|
|
599
|
+
return {
|
|
600
|
+
enabled: false,
|
|
601
|
+
ipaDir: "ios",
|
|
602
|
+
currentIpaFile: "",
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
function normalizeIosIpaConfig(input) {
|
|
606
|
+
if (!input || typeof input !== "object")
|
|
607
|
+
return undefined;
|
|
608
|
+
const defaults = defaultIosIpaConfig();
|
|
609
|
+
const iosInput = input;
|
|
610
|
+
return {
|
|
611
|
+
enabled: typeof iosInput.enabled === "boolean" ? iosInput.enabled : defaults.enabled,
|
|
612
|
+
ipaDir: typeof iosInput.ipaDir === "string" && iosInput.ipaDir.trim()
|
|
613
|
+
? iosInput.ipaDir.trim()
|
|
614
|
+
: defaults.ipaDir,
|
|
615
|
+
currentIpaFile: typeof iosInput.currentIpaFile === "string"
|
|
616
|
+
? iosInput.currentIpaFile.trim()
|
|
617
|
+
: defaults.currentIpaFile,
|
|
618
|
+
};
|
|
619
|
+
}
|
|
597
620
|
function normalizeStructuredChatPersona(input) {
|
|
598
621
|
if (!input || typeof input !== "object")
|
|
599
622
|
return undefined;
|
|
@@ -664,6 +687,7 @@ function mergeWithDefaults(input) {
|
|
|
664
687
|
: crypto.randomBytes(32).toString("hex"),
|
|
665
688
|
android: normalizeAndroidApkConfig(input.android) ?? defaults.android,
|
|
666
689
|
macos: normalizeMacosDmgConfig(input.macos) ?? defaults.macos,
|
|
690
|
+
ios: normalizeIosIpaConfig(input.ios) ?? defaults.ios,
|
|
667
691
|
cardDefaults: normalizeCardDefaults(input.cardDefaults),
|
|
668
692
|
defaultProvider: input.defaultProvider === "codex" || input.defaultProvider === "opencode" || input.defaultProvider === "grok" || input.defaultProvider === "qoder" || input.defaultProvider === "pi" ? input.defaultProvider : "claude",
|
|
669
693
|
defaultSessionKind: input.defaultSessionKind === "pty" ? "pty" : "structured",
|
|
@@ -22,6 +22,7 @@ export interface ResolvedDistributionAsset {
|
|
|
22
22
|
export interface DistributionSettings {
|
|
23
23
|
androidApk: Record<string, unknown>;
|
|
24
24
|
macosDmg: Record<string, unknown>;
|
|
25
|
+
iosIpa: Record<string, unknown>;
|
|
25
26
|
}
|
|
26
27
|
export interface DistributionManagerOptions {
|
|
27
28
|
configDir: string;
|
|
@@ -46,6 +47,8 @@ export declare class DistributionManager {
|
|
|
46
47
|
resolveAndroidDownload(channel?: ApkUpdateChannel): Promise<LocalDistributionAsset | null>;
|
|
47
48
|
resolveLatestDmg(): Promise<ResolvedDistributionAsset | null>;
|
|
48
49
|
resolveMacosDownload(): Promise<LocalDistributionAsset | null>;
|
|
50
|
+
resolveLatestIpa(): Promise<ResolvedDistributionAsset | null>;
|
|
51
|
+
resolveIosDownload(): Promise<LocalDistributionAsset | null>;
|
|
49
52
|
getSettings(): Promise<DistributionSettings>;
|
|
50
53
|
private readonly sha256Cache;
|
|
51
54
|
/**
|
|
@@ -114,18 +114,49 @@ export class DistributionManager {
|
|
|
114
114
|
compareVersions: compareSemver,
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
|
+
async resolveLatestIpa() {
|
|
118
|
+
const localIpa = await this.resolveIosDownload();
|
|
119
|
+
if (localIpa?.version) {
|
|
120
|
+
return {
|
|
121
|
+
version: localIpa.version,
|
|
122
|
+
downloadUrl: localIpa.downloadUrl,
|
|
123
|
+
fileName: localIpa.fileName,
|
|
124
|
+
size: localIpa.size,
|
|
125
|
+
source: "local",
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const github = await this.fetchGitHubAsset(".ipa");
|
|
129
|
+
return github ? { ...github, source: "github" } : null;
|
|
130
|
+
}
|
|
131
|
+
async resolveIosDownload() {
|
|
132
|
+
await this.refreshConfig();
|
|
133
|
+
const { config, configDir } = this.options;
|
|
134
|
+
if (config.ios?.enabled !== true)
|
|
135
|
+
return null;
|
|
136
|
+
return this.resolveLocalAsset({
|
|
137
|
+
directory: resolveConfiguredDir(configDir, config.ios.ipaDir, "ios"),
|
|
138
|
+
extension: ".ipa",
|
|
139
|
+
configuredFile: config.ios.currentIpaFile,
|
|
140
|
+
downloadUrl: "/ios/download",
|
|
141
|
+
compareVersions: compareSemver,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
117
144
|
async getSettings() {
|
|
118
|
-
const [localApk, githubApk, localDmg, githubDmg] = await Promise.all([
|
|
145
|
+
const [localApk, githubApk, localDmg, githubDmg, localIpa, githubIpa] = await Promise.all([
|
|
119
146
|
this.resolveAndroidDownload("beta"),
|
|
120
147
|
this.fetchGitHubAsset(".apk"),
|
|
121
148
|
this.resolveMacosDownload(),
|
|
122
149
|
this.fetchGitHubAsset(".dmg"),
|
|
150
|
+
this.resolveIosDownload(),
|
|
151
|
+
this.fetchGitHubAsset(".ipa"),
|
|
123
152
|
]);
|
|
124
153
|
const apkDir = resolveConfiguredDir(this.options.configDir, this.options.config.android?.apkDir, "android");
|
|
125
154
|
const dmgDir = resolveConfiguredDir(this.options.configDir, this.options.config.macos?.dmgDir, "macos");
|
|
155
|
+
const ipaDir = resolveConfiguredDir(this.options.configDir, this.options.config.ios?.ipaDir, "ios");
|
|
126
156
|
return {
|
|
127
157
|
androidApk: this.buildSettings("apk", apkDir, this.options.config.android?.enabled === true, localApk, githubApk),
|
|
128
158
|
macosDmg: this.buildSettings("dmg", dmgDir, this.options.config.macos?.enabled === true, localDmg, githubDmg),
|
|
159
|
+
iosIpa: this.buildSettings("ipa", ipaDir, this.options.config.ios?.enabled === true, localIpa, githubIpa),
|
|
129
160
|
};
|
|
130
161
|
}
|
|
131
162
|
sha256Cache = new Map();
|
|
@@ -181,6 +212,18 @@ export class DistributionManager {
|
|
|
181
212
|
config.macos.currentDmgFile = typeof macos.currentDmgFile === "string" ? macos.currentDmgFile.trim() : "";
|
|
182
213
|
}
|
|
183
214
|
}
|
|
215
|
+
const ios = asRecord(raw.ios);
|
|
216
|
+
if (ios) {
|
|
217
|
+
config.ios = { ...(config.ios ?? {}) };
|
|
218
|
+
if (typeof ios.enabled === "boolean")
|
|
219
|
+
config.ios.enabled = ios.enabled;
|
|
220
|
+
if (Object.hasOwn(ios, "ipaDir")) {
|
|
221
|
+
config.ios.ipaDir = typeof ios.ipaDir === "string" && ios.ipaDir.trim() ? ios.ipaDir.trim() : "ios";
|
|
222
|
+
}
|
|
223
|
+
if (Object.hasOwn(ios, "currentIpaFile")) {
|
|
224
|
+
config.ios.currentIpaFile = typeof ios.currentIpaFile === "string" ? ios.currentIpaFile.trim() : "";
|
|
225
|
+
}
|
|
226
|
+
}
|
|
184
227
|
}
|
|
185
228
|
async resolveLocalAsset(options) {
|
|
186
229
|
await mkdir(options.directory, { recursive: true });
|
|
@@ -295,8 +338,8 @@ export class DistributionManager {
|
|
|
295
338
|
: github
|
|
296
339
|
? { ...github, updatedAt: null, source: "github" }
|
|
297
340
|
: null;
|
|
298
|
-
const hasKey = kind === "apk" ? "hasApk" : "hasDmg";
|
|
299
|
-
const dirKey = kind === "apk" ? "apkDir" : "dmgDir";
|
|
341
|
+
const hasKey = kind === "apk" ? "hasApk" : kind === "dmg" ? "hasDmg" : "hasIpa";
|
|
342
|
+
const dirKey = kind === "apk" ? "apkDir" : kind === "dmg" ? "dmgDir" : "ipaDir";
|
|
300
343
|
return {
|
|
301
344
|
enabled,
|
|
302
345
|
[dirKey]: directory,
|
|
@@ -433,6 +433,16 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
433
433
|
res.status(409).json({ error: "会话列表已更新,请重新加载。", revision: page.revision });
|
|
434
434
|
return;
|
|
435
435
|
}
|
|
436
|
+
if (offset === 0 && requestedRevision && requestedRevision === page.revision) {
|
|
437
|
+
res.json({
|
|
438
|
+
unchanged: true,
|
|
439
|
+
entries: [],
|
|
440
|
+
offset: 0,
|
|
441
|
+
total: page.total,
|
|
442
|
+
revision: page.revision,
|
|
443
|
+
});
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
436
446
|
res.json(page);
|
|
437
447
|
}
|
|
438
448
|
catch (error) {
|
|
@@ -47,11 +47,13 @@ function publicSystemAi(systemAi) {
|
|
|
47
47
|
function publicDistributionInfo(distribution) {
|
|
48
48
|
const androidApk = { ...distribution.androidApk };
|
|
49
49
|
const macosDmg = { ...distribution.macosDmg };
|
|
50
|
+
const iosIpa = { ...distribution.iosIpa };
|
|
50
51
|
// These server filesystem paths are useful to administrators, but the About
|
|
51
52
|
// panel only needs versions, sizes, and download URLs.
|
|
52
53
|
delete androidApk.apkDir;
|
|
53
54
|
delete macosDmg.dmgDir;
|
|
54
|
-
|
|
55
|
+
delete iosIpa.ipaDir;
|
|
56
|
+
return { androidApk, macosDmg, iosIpa };
|
|
55
57
|
}
|
|
56
58
|
export function registerSettingsRoutes(app, deps) {
|
|
57
59
|
const { storage, config, runtimeConfig, configPath, configDir, requireAdmin, requireAdminOrSessionPreferences, } = deps;
|
|
@@ -23,6 +23,8 @@ export interface PublicUpdateRoutesDependencies {
|
|
|
23
23
|
resolveAndroidDownload(channel: "stable" | "beta"): Promise<DownloadAsset | null>;
|
|
24
24
|
resolveLatestDmg(): Promise<ResolvedUpdateAsset | null>;
|
|
25
25
|
resolveMacosDownload(): Promise<DownloadAsset | null>;
|
|
26
|
+
resolveLatestIpa(): Promise<ResolvedUpdateAsset | null>;
|
|
27
|
+
resolveIosDownload(): Promise<DownloadAsset | null>;
|
|
26
28
|
}
|
|
27
29
|
export declare function registerPublicUpdateRoutes(app: Express, deps: PublicUpdateRoutesDependencies): void;
|
|
28
30
|
export declare class ServerUpdateState {
|
|
@@ -46,6 +48,7 @@ export interface AdminUpdateRoutesDependencies {
|
|
|
46
48
|
getDistributionSettings(): Promise<{
|
|
47
49
|
androidApk: Record<string, unknown>;
|
|
48
50
|
macosDmg: Record<string, unknown>;
|
|
51
|
+
iosIpa: Record<string, unknown>;
|
|
49
52
|
}>;
|
|
50
53
|
modelCatalog: ModelCatalogService;
|
|
51
54
|
getUpdateChannel(): UpdateChannel;
|
|
@@ -86,6 +86,20 @@ export function registerPublicUpdateRoutes(app, deps) {
|
|
|
86
86
|
readErrorMessage: "读取 DMG 文件失败。",
|
|
87
87
|
});
|
|
88
88
|
}));
|
|
89
|
+
app.get("/ios/download", asyncRoute(async (req, res) => {
|
|
90
|
+
const asset = await deps.resolveIosDownload();
|
|
91
|
+
if (!asset) {
|
|
92
|
+
res.status(404).json({ error: "当前没有可下载的 IPA 文件。" });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
streamFileWithRange(req, res, {
|
|
96
|
+
filePath: asset.filePath,
|
|
97
|
+
size: asset.size,
|
|
98
|
+
contentType: "application/octet-stream",
|
|
99
|
+
disposition: `attachment; filename="${encodeURIComponent(asset.fileName)}"`,
|
|
100
|
+
readErrorMessage: "读取 IPA 文件失败。",
|
|
101
|
+
});
|
|
102
|
+
}));
|
|
89
103
|
}
|
|
90
104
|
export class ServerUpdateState {
|
|
91
105
|
providerCliUpdateCache = null;
|
|
@@ -106,6 +120,9 @@ export function registerAdminUpdateRoutes(app, deps) {
|
|
|
106
120
|
app.get("/api/macos-dmg", requireAdmin, asyncRoute(async (_req, res) => {
|
|
107
121
|
res.json((await deps.getDistributionSettings()).macosDmg);
|
|
108
122
|
}));
|
|
123
|
+
app.get("/api/ios-ipa", requireAdmin, asyncRoute(async (_req, res) => {
|
|
124
|
+
res.json((await deps.getDistributionSettings()).iosIpa);
|
|
125
|
+
}));
|
|
109
126
|
app.get("/api/provider-cli-updates", requireAdmin, asyncRoute(async (req, res) => {
|
|
110
127
|
try {
|
|
111
128
|
const force = req.query.refresh === "1" || !state.providerCliUpdateCache;
|
package/dist/types.d.ts
CHANGED
|
@@ -70,6 +70,11 @@ export interface MacosDmgConfig {
|
|
|
70
70
|
dmgDir?: string;
|
|
71
71
|
currentDmgFile?: string;
|
|
72
72
|
}
|
|
73
|
+
export interface IosIpaConfig {
|
|
74
|
+
enabled?: boolean;
|
|
75
|
+
ipaDir?: string;
|
|
76
|
+
currentIpaFile?: string;
|
|
77
|
+
}
|
|
73
78
|
export interface WandConfig {
|
|
74
79
|
host: string;
|
|
75
80
|
port: number;
|
|
@@ -104,6 +109,7 @@ export interface WandConfig {
|
|
|
104
109
|
appSecret?: string;
|
|
105
110
|
android?: AndroidApkConfig;
|
|
106
111
|
macos?: MacosDmgConfig;
|
|
112
|
+
ios?: IosIpaConfig;
|
|
107
113
|
/** Default expand/collapse state for card types in structured chat view */
|
|
108
114
|
cardDefaults?: CardExpandDefaults;
|
|
109
115
|
/** 新建会话时默认使用的 Claude 模型(别名或完整 ID)。留空则不传 --model,由 claude 自行决定。 */
|