@co0ontty/wand 4.45.0 → 4.45.1
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.d.ts +1 -8
- package/dist/config.js +2 -2
- package/dist/distribution-manager.d.ts +5 -0
- package/dist/distribution-manager.js +13 -0
- package/dist/message-truncator.d.ts +0 -15
- package/dist/message-truncator.js +2 -2
- package/dist/middleware/rate-limit.d.ts +0 -1
- package/dist/middleware/rate-limit.js +1 -1
- package/dist/mission-types.d.ts +2 -1
- package/dist/models.d.ts +6 -5
- package/dist/npm-update-utils.d.ts +0 -17
- package/dist/npm-update-utils.js +5 -5
- package/dist/password-manager.d.ts +2 -5
- package/dist/password-manager.js +4 -4
- package/dist/pidfile.d.ts +0 -1
- package/dist/pidfile.js +1 -1
- package/dist/server-session-routes.d.ts +1 -2
- package/dist/server-session-routes.js +1 -1
- package/dist/server-update-routes.d.ts +2 -0
- package/dist/server-update-routes.js +7 -0
- package/dist/server.d.ts +2 -1
- package/dist/session-transport.d.ts +2 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +1 -1
- package/dist/structured-claude-adapter.d.ts +2 -1
- package/dist/structured-claude-protocol.d.ts +0 -1
- package/dist/structured-claude-protocol.js +1 -1
- package/dist/structured-codex-protocol.d.ts +1 -1
- package/dist/structured-opencode-adapter.d.ts +0 -1
- package/dist/structured-opencode-adapter.js +1 -1
- package/dist/structured-session-manager.d.ts +1 -1
- package/dist/structured-session-manager.js +0 -1
- package/dist/system-ai.d.ts +0 -4
- package/dist/system-ai.js +1 -1
- package/dist/terminal-daemon-protocol.d.ts +0 -1
- package/dist/terminal-daemon-protocol.js +0 -4
- package/dist/tui/commands.d.ts +0 -1
- package/dist/tui/commands.js +1 -1
- package/dist/tui/index.d.ts +2 -1
- package/dist/tui/layout.d.ts +4 -3
- package/dist/tui/session-formatter.d.ts +0 -2
- package/dist/tui/session-formatter.js +1 -1
- package/dist/types.d.ts +17 -20
- package/dist/version-utils.d.ts +0 -2
- package/dist/version-utils.js +1 -1
- package/dist/web-ui/content/scripts.js +1 -1
- package/dist/web-ui/embedded-assets.d.ts +1 -1
- package/dist/web-ui/embedded-assets.js +2 -2
- package/dist/web-ui/index.d.ts +0 -2
- package/dist/web-ui/index.js +1 -1
- package/dist/workspace-binding.d.ts +0 -1
- package/dist/workspace-binding.js +1 -1
- package/package.json +1 -6
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commit": "
|
|
3
|
-
"builtAt": "2026-08-
|
|
4
|
-
"version": "4.45.
|
|
2
|
+
"commit": "1a79f31b6f38f7a7a2a83ce85c78db126b9f5f47",
|
|
3
|
+
"builtAt": "2026-08-22T07:39:53.924Z",
|
|
4
|
+
"version": "4.45.1",
|
|
5
5
|
"channel": "stable"
|
|
6
6
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ExecutionMode, SessionProvider, WandConfig } from "./types.js";
|
|
2
2
|
import type { WandStorage } from "./storage.js";
|
|
3
3
|
/**
|
|
4
4
|
* 通过 UI 设置面板可改的"用户偏好"字段。这些字段从 SQLite app_config 表读取,
|
|
@@ -25,12 +25,6 @@ export declare function saveConfig(configPath: string, config: WandConfig): Prom
|
|
|
25
25
|
* 5. 如果 JSON 里仍含偏好字段(来自 1),用 saveConfig 重写一次 JSON(剥离后)
|
|
26
26
|
*/
|
|
27
27
|
export declare function loadConfigWithStorage(configPath: string, storage: WandStorage): Promise<WandConfig>;
|
|
28
|
-
/**
|
|
29
|
-
* 老版本 JSON 里如果还存有偏好字段,且 DB 里对应 key 没有写过,
|
|
30
|
-
* 把 JSON 的值搬到 DB。注意:必须在 mergeWithDefaults 之前操作 raw input,
|
|
31
|
-
* 这样能区分"用户显式写过 X" 和 "X 是 mergeWithDefaults 注入的默认值"。
|
|
32
|
-
*/
|
|
33
|
-
export declare function migrateLegacyPreferencesToDb(rawJsonInput: Partial<WandConfig> | null | undefined, storage: WandStorage): void;
|
|
34
28
|
/**
|
|
35
29
|
* 用 DB 里的偏好覆盖 config 对象(in-place),返回同一个引用,
|
|
36
30
|
* 方便各 manager 持有引用后继续工作。DB 里没有的字段不动,保留 JSON 默认值。
|
|
@@ -46,7 +40,6 @@ export declare function writePreferenceToStorage(config: WandConfig, storage: Wa
|
|
|
46
40
|
* so selecting API is valid even when no manual systemAi profile is stored.
|
|
47
41
|
*/
|
|
48
42
|
export declare function validateCommitAiConfig(_config: Pick<WandConfig, "commitAiSource" | "systemAi">): void;
|
|
49
|
-
export declare function normalizeCardDefaults(input: unknown): CardExpandDefaults;
|
|
50
43
|
export declare function isExecutionMode(value: unknown): value is ExecutionMode;
|
|
51
44
|
export declare function getProviderDefaultModels(config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel" | "defaultGrokModel" | "defaultQoderModel" | "defaultPiModel">): {
|
|
52
45
|
claude: string;
|
package/dist/config.js
CHANGED
|
@@ -265,7 +265,7 @@ function stripPreferenceFields(config) {
|
|
|
265
265
|
* 把 JSON 的值搬到 DB。注意:必须在 mergeWithDefaults 之前操作 raw input,
|
|
266
266
|
* 这样能区分"用户显式写过 X" 和 "X 是 mergeWithDefaults 注入的默认值"。
|
|
267
267
|
*/
|
|
268
|
-
|
|
268
|
+
function migrateLegacyPreferencesToDb(rawJsonInput, storage) {
|
|
269
269
|
if (!rawJsonInput || typeof rawJsonInput !== "object")
|
|
270
270
|
return;
|
|
271
271
|
for (const key of PREFERENCE_KEYS) {
|
|
@@ -539,7 +539,7 @@ function defaultCardExpandDefaults() {
|
|
|
539
539
|
toolGroup: false,
|
|
540
540
|
};
|
|
541
541
|
}
|
|
542
|
-
|
|
542
|
+
function normalizeCardDefaults(input) {
|
|
543
543
|
if (!input || typeof input !== "object")
|
|
544
544
|
return defaultCardExpandDefaults();
|
|
545
545
|
const raw = input;
|
|
@@ -51,6 +51,11 @@ export declare class DistributionManager {
|
|
|
51
51
|
resolveIosDownload(): Promise<LocalDistributionAsset | null>;
|
|
52
52
|
getSettings(): Promise<DistributionSettings>;
|
|
53
53
|
private readonly sha256Cache;
|
|
54
|
+
/**
|
|
55
|
+
* 计算本地分发资产的 SHA-256(hex),供下载路由写入 X-APK-Sha256 响应头。
|
|
56
|
+
* 计算失败返回 null,调用方按无哈希处理。
|
|
57
|
+
*/
|
|
58
|
+
computeAssetSha256(asset: LocalDistributionAsset): Promise<string | null>;
|
|
54
59
|
/**
|
|
55
60
|
* 计算本地分发文件的 SHA-256(hex)。按 path + size + mtime 缓存:更新检查
|
|
56
61
|
* 可能被多个客户端频繁触发,避免每次都全量读盘。
|
|
@@ -160,6 +160,19 @@ export class DistributionManager {
|
|
|
160
160
|
};
|
|
161
161
|
}
|
|
162
162
|
sha256Cache = new Map();
|
|
163
|
+
/**
|
|
164
|
+
* 计算本地分发资产的 SHA-256(hex),供下载路由写入 X-APK-Sha256 响应头。
|
|
165
|
+
* 计算失败返回 null,调用方按无哈希处理。
|
|
166
|
+
*/
|
|
167
|
+
async computeAssetSha256(asset) {
|
|
168
|
+
try {
|
|
169
|
+
const fileStat = await stat(asset.filePath);
|
|
170
|
+
return await this.computeLocalFileSha256(asset.filePath, fileStat.size, fileStat.mtimeMs);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
163
176
|
/**
|
|
164
177
|
* 计算本地分发文件的 SHA-256(hex)。按 path + size + mtime 缓存:更新检查
|
|
165
178
|
* 可能被多个客户端频繁触发,避免每次都全量读盘。
|
|
@@ -4,21 +4,6 @@
|
|
|
4
4
|
* with a summary, and clients fetch full content on-demand via API.
|
|
5
5
|
*/
|
|
6
6
|
import type { CardExpandDefaults, ContentBlock, ConversationTurn } from "./types.js";
|
|
7
|
-
/**
|
|
8
|
-
* 默认窗口大小:init/resync/快照/REST 默认只下发最近这么多条 turn,更早的由客户端
|
|
9
|
-
* 滚动到顶时按需分页拉取。移动端 WebSocket 单帧上限(iOS 默认 1 MiB)下,长会话一次
|
|
10
|
-
* 全量下发会撑爆帧导致反复断连——窗口化是根治手段,64MB 提帧只是兜底。
|
|
11
|
-
*/
|
|
12
|
-
export declare const MESSAGE_WINDOW_SIZE = 40;
|
|
13
|
-
/**
|
|
14
|
-
* 块级窗口的默认预算:init/REST 默认只下发最近这么多个「内容块」(跨 turn 累计,
|
|
15
|
-
* 必要时切掉最旧那条 turn 的头部),更早的块由客户端滚动到顶时按需分页拉取。
|
|
16
|
-
* turn 级窗口(MESSAGE_WINDOW_SIZE)对「单条 turn 携带上百块」的长任务无能为力——
|
|
17
|
-
* 一条流式 assistant turn 可膨胀到 1MB+,整条下发会撑爆移动端 WS 帧、拖慢打开。
|
|
18
|
-
* 块级窗口是对这种会话的根治手段。仅在客户端显式带 blockBudget 时启用(iOS),
|
|
19
|
-
* Web/Android 走原有 turn 级路径不受影响。
|
|
20
|
-
*/
|
|
21
|
-
export declare const MESSAGE_BLOCK_WINDOW = 60;
|
|
22
7
|
export interface WindowedMessages {
|
|
23
8
|
/** 已截断 + 窗口化后的 turn 列表(最近 windowSize 条)。 */
|
|
24
9
|
messages: ConversationTurn[];
|
|
@@ -10,7 +10,7 @@ const SUMMARY_LENGTH = 100;
|
|
|
10
10
|
* 滚动到顶时按需分页拉取。移动端 WebSocket 单帧上限(iOS 默认 1 MiB)下,长会话一次
|
|
11
11
|
* 全量下发会撑爆帧导致反复断连——窗口化是根治手段,64MB 提帧只是兜底。
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
const MESSAGE_WINDOW_SIZE = 40;
|
|
14
14
|
/**
|
|
15
15
|
* 块级窗口的默认预算:init/REST 默认只下发最近这么多个「内容块」(跨 turn 累计,
|
|
16
16
|
* 必要时切掉最旧那条 turn 的头部),更早的块由客户端滚动到顶时按需分页拉取。
|
|
@@ -19,7 +19,7 @@ export const MESSAGE_WINDOW_SIZE = 40;
|
|
|
19
19
|
* 块级窗口是对这种会话的根治手段。仅在客户端显式带 blockBudget 时启用(iOS),
|
|
20
20
|
* Web/Android 走原有 turn 级路径不受影响。
|
|
21
21
|
*/
|
|
22
|
-
|
|
22
|
+
const MESSAGE_BLOCK_WINDOW = 60;
|
|
23
23
|
/**
|
|
24
24
|
* 块级窗口:取完整历史「最近 blockBudget 个内容块」并做 transport 截断。
|
|
25
25
|
* 从最新 turn 往回累计块数,能整条放下就整条放,放不下的那条(最旧的入窗 turn)
|
|
@@ -25,7 +25,7 @@ export function recordFailedLogin(ip) {
|
|
|
25
25
|
export function resetRateLimit(ip) {
|
|
26
26
|
loginAttempts.delete(ip);
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
function cleanupRateLimiter() {
|
|
29
29
|
const now = Date.now();
|
|
30
30
|
for (const [ip, record] of loginAttempts.entries()) {
|
|
31
31
|
if (now > record.resetAt) {
|
package/dist/mission-types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type AgentActivityState = "working" | "needs_input" | "needs_permission"
|
|
|
3
3
|
export type MissionStatus = "dispatching" | "running" | "needs_input" | "completed" | "failed" | "archived";
|
|
4
4
|
export type MissionAttemptState = AgentActivityState | "queued";
|
|
5
5
|
export type MissionReviewStatus = "pending" | "sent" | "resolved";
|
|
6
|
-
|
|
6
|
+
interface MissionWorktreeOptions {
|
|
7
7
|
baseRef?: string;
|
|
8
8
|
sharedDirectories?: string[];
|
|
9
9
|
copyPaths?: string[];
|
|
@@ -88,3 +88,4 @@ export interface CreateReviewCommentInput {
|
|
|
88
88
|
side?: "old" | "new";
|
|
89
89
|
body: string;
|
|
90
90
|
}
|
|
91
|
+
export {};
|
package/dist/models.d.ts
CHANGED
|
@@ -5,24 +5,24 @@ import { ClaudeModelInfo } from "./types.js";
|
|
|
5
5
|
* provider, whereas the latter records evidence from individual probes.
|
|
6
6
|
*/
|
|
7
7
|
export declare const MODEL_CATALOG_CACHE_KEY = "model-catalog-v1";
|
|
8
|
-
|
|
8
|
+
interface ModelCacheStorage {
|
|
9
9
|
getConfigValue(key: string): string | null;
|
|
10
10
|
setConfigValue(key: string, value: string): void;
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
interface ModelCommandOptions {
|
|
13
13
|
env: NodeJS.ProcessEnv;
|
|
14
14
|
timeout: number;
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
interface ModelCommandResult {
|
|
17
17
|
stdout: string;
|
|
18
18
|
stderr: string;
|
|
19
19
|
}
|
|
20
20
|
export type ModelCommandRunner = (file: string, args: string[], options: ModelCommandOptions) => Promise<ModelCommandResult>;
|
|
21
|
-
|
|
21
|
+
interface ClaudeModelsApiEntry {
|
|
22
22
|
id: string;
|
|
23
23
|
display_name?: string;
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
interface ClaudeModelsApi {
|
|
26
26
|
list(): AsyncIterable<ClaudeModelsApiEntry>;
|
|
27
27
|
}
|
|
28
28
|
export interface ModelRefreshOptions {
|
|
@@ -108,3 +108,4 @@ export declare class ModelCatalogService {
|
|
|
108
108
|
* use `ModelCatalogService` so the result is persisted and diffed.
|
|
109
109
|
*/
|
|
110
110
|
export declare function refreshModels(options?: ModelRefreshOptions): Promise<ModelCache>;
|
|
111
|
+
export {};
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
* 我们的策略:安装前备份当前全局包,补齐 npm 子进程 PATH,清掉
|
|
12
12
|
* `@co0ontty/.wand-*` 残留目录;失败时恢复备份,避免运行中的服务被半成品安装拆掉。
|
|
13
13
|
*/
|
|
14
|
-
export declare const PACKAGE_NAME = "@co0ontty/wand";
|
|
15
14
|
export type UpdateChannel = "stable" | "beta";
|
|
16
15
|
export interface PackageUpdateInfo {
|
|
17
16
|
channel: UpdateChannel;
|
|
@@ -22,26 +21,10 @@ export interface PackageUpdateInfo {
|
|
|
22
21
|
installSpec: string;
|
|
23
22
|
}
|
|
24
23
|
export declare function normalizeUpdateChannel(value: unknown): UpdateChannel;
|
|
25
|
-
export declare function getUpdateDistTag(channel: UpdateChannel): "latest" | "beta";
|
|
26
24
|
export declare function getInstallSpecForChannel(channel: UpdateChannel): string;
|
|
27
|
-
export declare function getStableTagVersion(version: string): string;
|
|
28
25
|
export declare function buildPackageUpdateInfo(currentVersion: string, channel: UpdateChannel, latestVersion: string | null): PackageUpdateInfo;
|
|
29
26
|
export declare function checkPackageUpdateAsync(currentVersion: string, channel: UpdateChannel, timeoutMs?: number): Promise<PackageUpdateInfo>;
|
|
30
27
|
export declare function checkPackageUpdateSync(currentVersion: string, channel: UpdateChannel, timeoutMs?: number): PackageUpdateInfo;
|
|
31
|
-
/**
|
|
32
|
-
* 解析当前 `npm root -g` 的目录。失败返回 null。
|
|
33
|
-
*/
|
|
34
|
-
export declare function getNpmGlobalRoot(): string | null;
|
|
35
|
-
/**
|
|
36
|
-
* 清理上一次 npm install 失败留下的 `.wand-XXXXXX` 残留目录。
|
|
37
|
-
*
|
|
38
|
-
* 同步执行,best-effort:找不到 npm root、目录不存在、无权限删除等都不会抛错。
|
|
39
|
-
* 返回被清理的目录列表,方便调用方记录日志。
|
|
40
|
-
*/
|
|
41
|
-
export declare function cleanupNpmLeftovers(): {
|
|
42
|
-
removed: string[];
|
|
43
|
-
errors: string[];
|
|
44
|
-
};
|
|
45
28
|
/**
|
|
46
29
|
* 更新时同时存在旧包备份、npm 正在解包的新版本和下载/回滚余量。
|
|
47
30
|
* 旧包大小按三倍计(安全备份、新包、回滚 staging),再保留 512 MiB,
|
package/dist/npm-update-utils.js
CHANGED
|
@@ -21,7 +21,7 @@ import { whichSync } from "./path-repair.js";
|
|
|
21
21
|
import { getErrorMessage } from "./error-utils.js";
|
|
22
22
|
import { compareWandInstallOrder, extractSemver } from "./version-utils.js";
|
|
23
23
|
const execFileAsync = promisify(execFile);
|
|
24
|
-
|
|
24
|
+
const PACKAGE_NAME = "@co0ontty/wand";
|
|
25
25
|
const PACKAGE_SCOPE = "@co0ontty";
|
|
26
26
|
const PACKAGE_BASENAME = "wand";
|
|
27
27
|
const DEFAULT_NPM_BIN = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
@@ -35,7 +35,7 @@ function npmBin() {
|
|
|
35
35
|
export function normalizeUpdateChannel(value) {
|
|
36
36
|
return value === "beta" ? "beta" : "stable";
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
function getUpdateDistTag(channel) {
|
|
39
39
|
return channel === "beta" ? "beta" : "latest";
|
|
40
40
|
}
|
|
41
41
|
export function getInstallSpecForChannel(channel) {
|
|
@@ -44,7 +44,7 @@ export function getInstallSpecForChannel(channel) {
|
|
|
44
44
|
function cleanVersion(value) {
|
|
45
45
|
return value.trim().replace(/^v/, "");
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
function getStableTagVersion(version) {
|
|
48
48
|
return cleanVersion(version).split("+")[0]?.split("-")[0] ?? cleanVersion(version);
|
|
49
49
|
}
|
|
50
50
|
function computeUpdateAvailable(currentVersion, latestVersion, channel) {
|
|
@@ -138,7 +138,7 @@ async function runNpmAsync(args, timeoutMs) {
|
|
|
138
138
|
/**
|
|
139
139
|
* 解析当前 `npm root -g` 的目录。失败返回 null。
|
|
140
140
|
*/
|
|
141
|
-
|
|
141
|
+
function getNpmGlobalRoot() {
|
|
142
142
|
try {
|
|
143
143
|
const res = runNpmSync(["root", "-g"], 10_000);
|
|
144
144
|
if (res.status !== 0)
|
|
@@ -190,7 +190,7 @@ function pathEntryExists(targetPath) {
|
|
|
190
190
|
* 同步执行,best-effort:找不到 npm root、目录不存在、无权限删除等都不会抛错。
|
|
191
191
|
* 返回被清理的目录列表,方便调用方记录日志。
|
|
192
192
|
*/
|
|
193
|
-
|
|
193
|
+
function cleanupNpmLeftovers() {
|
|
194
194
|
const removed = [];
|
|
195
195
|
const errors = [];
|
|
196
196
|
const root = getNpmGlobalRoot();
|
|
@@ -45,7 +45,7 @@ export interface PasswordVaultItemFilter {
|
|
|
45
45
|
includeArchived?: boolean;
|
|
46
46
|
limit?: number;
|
|
47
47
|
}
|
|
48
|
-
|
|
48
|
+
interface PasswordIssue {
|
|
49
49
|
itemId: string;
|
|
50
50
|
title: string;
|
|
51
51
|
kind: "weak_password" | "reused_password" | "missing_url" | "old_password" | "passkey_available";
|
|
@@ -66,9 +66,6 @@ export declare function nowIso(): string;
|
|
|
66
66
|
export declare function normalizePasswordItemType(value: unknown): PasswordVaultItemType;
|
|
67
67
|
export declare function normalizeVaultName(value: unknown): string;
|
|
68
68
|
export declare function normalizePasswordItemInput(input: PasswordVaultItemInput): Required<Pick<PasswordVaultItemInput, "type" | "title" | "urls" | "fields" | "tags" | "favorite">> & PasswordVaultItemInput;
|
|
69
|
-
export declare function normalizeUrls(urls: unknown): string[];
|
|
70
|
-
export declare function normalizeStoredUrl(value: string): string | null;
|
|
71
|
-
export declare function urlsMatch(storedUrl: string, pageUrl: string): boolean;
|
|
72
69
|
export declare function itemMatchesFilter(item: PasswordVaultItem, filter: PasswordVaultItemFilter): boolean;
|
|
73
70
|
export declare function scorePasswordStrength(password: string | undefined): number;
|
|
74
71
|
export declare function buildPasswordSecurityReport(items: PasswordVaultItem[], now?: number): PasswordSecurityReport;
|
|
@@ -83,4 +80,4 @@ export declare function decryptVaultSecret(value: string | undefined, secret: st
|
|
|
83
80
|
export declare function isEncryptedVaultSecret(value: string | undefined): boolean;
|
|
84
81
|
export declare function generatePassword(options?: PasswordGeneratorOptions): string;
|
|
85
82
|
export declare function generateTotpCode(secret: string, timeMs?: number, digits?: number, period?: number): string;
|
|
86
|
-
export
|
|
83
|
+
export {};
|
package/dist/password-manager.js
CHANGED
|
@@ -59,7 +59,7 @@ export function normalizePasswordItemInput(input) {
|
|
|
59
59
|
favorite: input.favorite === true,
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
function normalizeUrls(urls) {
|
|
63
63
|
if (!Array.isArray(urls))
|
|
64
64
|
return [];
|
|
65
65
|
const out = [];
|
|
@@ -72,7 +72,7 @@ export function normalizeUrls(urls) {
|
|
|
72
72
|
}
|
|
73
73
|
return out.slice(0, 20);
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
function normalizeStoredUrl(value) {
|
|
76
76
|
const raw = value.trim();
|
|
77
77
|
if (!raw)
|
|
78
78
|
return null;
|
|
@@ -89,7 +89,7 @@ export function normalizeStoredUrl(value) {
|
|
|
89
89
|
return null;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
|
|
92
|
+
function urlsMatch(storedUrl, pageUrl) {
|
|
93
93
|
try {
|
|
94
94
|
const stored = new URL(normalizeStoredUrl(storedUrl) ?? storedUrl);
|
|
95
95
|
const page = new URL(pageUrl);
|
|
@@ -307,7 +307,7 @@ export function generateTotpCode(secret, timeMs = Date.now(), digits = 6, period
|
|
|
307
307
|
| (digest[offset + 3] & 0xff)) % (10 ** digits);
|
|
308
308
|
return String(code).padStart(digits, "0");
|
|
309
309
|
}
|
|
310
|
-
|
|
310
|
+
function decodeTotpSecret(secret) {
|
|
311
311
|
const cleaned = secret.replace(/\s+/g, "").replace(/=+$/g, "").toUpperCase();
|
|
312
312
|
if (!cleaned)
|
|
313
313
|
throw new Error("TOTP secret is required.");
|
package/dist/pidfile.d.ts
CHANGED
|
@@ -24,7 +24,6 @@ export interface PidInfo {
|
|
|
24
24
|
/** Unix socket 绝对路径;Windows 下为空字符串。 */
|
|
25
25
|
socket: string;
|
|
26
26
|
}
|
|
27
|
-
export declare function pidfilePath(configPath: string): string;
|
|
28
27
|
export declare function socketPath(configPath: string): string;
|
|
29
28
|
/** 原子写:先写到 .tmp 再 rename。 */
|
|
30
29
|
export declare function writePidfile(configPath: string, info: PidInfo): void;
|
package/dist/pidfile.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { chmodSync, chownSync, existsSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
15
15
|
import path from "node:path";
|
|
16
16
|
import process from "node:process";
|
|
17
|
-
|
|
17
|
+
function pidfilePath(configPath) {
|
|
18
18
|
return path.resolve(path.dirname(configPath), "wand.pid");
|
|
19
19
|
}
|
|
20
20
|
export function socketPath(configPath) {
|
|
@@ -32,7 +32,7 @@ type ProviderHistorySession = {
|
|
|
32
32
|
managedByWand: boolean;
|
|
33
33
|
provider?: "claude" | "codex" | "opencode" | "qoder";
|
|
34
34
|
};
|
|
35
|
-
|
|
35
|
+
type SessionListPageEntry = {
|
|
36
36
|
type: "managed";
|
|
37
37
|
key: string;
|
|
38
38
|
sortTimestamp: number;
|
|
@@ -53,7 +53,6 @@ export interface SessionDirectoryTreeResponse {
|
|
|
53
53
|
/** Full directory-tree revision, including custom workspace names. */
|
|
54
54
|
treeRevision: string;
|
|
55
55
|
}
|
|
56
|
-
export declare function buildSessionListEntries(sessions: SessionSnapshot[]): SessionListPageEntry[];
|
|
57
56
|
export declare function buildSessionListPage(sessions: SessionSnapshot[], offset: number, limit: number): SessionListPage;
|
|
58
57
|
export declare function buildSessionDirectoryTree(sessions: SessionSnapshot[], customNames?: ReadonlyMap<string, string>): SessionDirectoryTreeResponse;
|
|
59
58
|
/**
|
|
@@ -198,7 +198,7 @@ function sessionSortTimestamp(snapshot) {
|
|
|
198
198
|
const timestamp = Date.parse(snapshot.startedAt);
|
|
199
199
|
return Number.isFinite(timestamp) ? timestamp : 0;
|
|
200
200
|
}
|
|
201
|
-
|
|
201
|
+
function buildSessionListEntries(sessions) {
|
|
202
202
|
return sessions.map((session) => ({
|
|
203
203
|
type: "managed",
|
|
204
204
|
key: `session-${session.id}`,
|
|
@@ -21,6 +21,8 @@ interface ResolvedUpdateAsset {
|
|
|
21
21
|
export interface PublicUpdateRoutesDependencies {
|
|
22
22
|
resolveLatestApk(channel: "stable" | "beta"): Promise<ResolvedUpdateAsset | null>;
|
|
23
23
|
resolveAndroidDownload(channel: "stable" | "beta"): Promise<DownloadAsset | null>;
|
|
24
|
+
/** 计算本地分发文件的 SHA-256(hex);失败返回 null,下载响应不带哈希头。 */
|
|
25
|
+
computeAssetSha256(asset: DownloadAsset): Promise<string | null>;
|
|
24
26
|
resolveLatestDmg(): Promise<ResolvedUpdateAsset | null>;
|
|
25
27
|
resolveMacosDownload(): Promise<DownloadAsset | null>;
|
|
26
28
|
resolveLatestIpa(): Promise<ResolvedUpdateAsset | null>;
|
|
@@ -42,11 +42,18 @@ export function registerPublicUpdateRoutes(app, deps) {
|
|
|
42
42
|
res.status(404).json({ error: "当前没有可下载的 APK 文件。" });
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
|
+
// 响应头携带实际发送字节的 SHA-256:check 与 download 之间 APK 目录若被
|
|
46
|
+
// 重新构建/覆盖,客户端以响应头为准,避免用过期 check 快照误报校验失败。
|
|
47
|
+
const headers = {};
|
|
48
|
+
const sha256 = await deps.computeAssetSha256(asset).catch(() => null);
|
|
49
|
+
if (sha256)
|
|
50
|
+
headers["X-APK-Sha256"] = sha256;
|
|
45
51
|
streamFileWithRange(req, res, {
|
|
46
52
|
filePath: asset.filePath,
|
|
47
53
|
size: asset.size,
|
|
48
54
|
contentType: "application/vnd.android.package-archive",
|
|
49
55
|
disposition: `attachment; filename="${encodeURIComponent(asset.fileName)}"`,
|
|
56
|
+
headers,
|
|
50
57
|
readErrorMessage: "读取 APK 文件失败。",
|
|
51
58
|
});
|
|
52
59
|
}));
|
package/dist/server.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { StructuredSessionManager } from "./structured-session-manager.js";
|
|
|
5
5
|
import { type PathRepairResult } from "./path-repair.js";
|
|
6
6
|
import type { TerminalHost } from "./terminal-host.js";
|
|
7
7
|
import { WandConfig } from "./types.js";
|
|
8
|
-
|
|
8
|
+
interface ServerUrl {
|
|
9
9
|
url: string;
|
|
10
10
|
scheme: "HTTP" | "HTTPS";
|
|
11
11
|
}
|
|
@@ -34,3 +34,4 @@ export declare function startServer(config: WandConfig, configPath: string, opti
|
|
|
34
34
|
modelRefreshOptions?: () => Partial<ModelRefreshOptions>;
|
|
35
35
|
terminalHost?: TerminalHost;
|
|
36
36
|
}): Promise<ServerHandle>;
|
|
37
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ConversationTurn, SessionSnapshot } from "./types.js";
|
|
2
2
|
export declare const SESSION_TRANSPORT_OUTPUT_LIMIT = 200000;
|
|
3
|
-
|
|
3
|
+
type SessionBaseDTO = Omit<SessionSnapshot, "output" | "messages" | "title" | "ptyOutputSeq" | "ptyLaunchMarkerToken"> & {
|
|
4
4
|
/** Canonical server-resolved title. Clients must not invent their own fallback. */
|
|
5
5
|
title: string;
|
|
6
6
|
/** Alias of claudeSessionId; that field stores every provider's native resume id. */
|
|
@@ -37,3 +37,4 @@ export interface SessionDetailDTOOptions {
|
|
|
37
37
|
export declare function toSessionDetailDTO(snapshot: SessionSnapshot, options?: SessionDetailDTOOptions): SessionDetailDTO;
|
|
38
38
|
/** Bound snapshot-like event payloads before they enter per-client WS queues. */
|
|
39
39
|
export declare function boundSessionEventData(data: unknown, outputLimit?: number): unknown;
|
|
40
|
+
export {};
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { SessionSnapshot, ConversationTurn, StructuredSessionState, Workspace, LayoutNode, TaskWindowLayout, WorkspaceDefaultProvider, WorkspaceTask, WorkspaceTaskWorktree, WorkspaceTaskStatus } from "./types.js";
|
|
2
2
|
import type { AgentActivityItem, Mission, MissionAttempt, MissionReviewComment, MissionReviewStatus, MissionStatus } from "./mission-types.js";
|
|
3
3
|
import { type PasswordVault, type PasswordVaultItem, type PasswordVaultItemFilter, type PasswordVaultItemInput } from "./password-manager.js";
|
|
4
|
-
|
|
5
|
-
export type AuthPrincipalKind = "browser-admin" | "connected-app";
|
|
4
|
+
type AuthPrincipalKind = "browser-admin" | "connected-app";
|
|
6
5
|
export type AuthScope = "admin" | "sessions" | "files" | "password-vault" | "session-preferences";
|
|
7
6
|
export interface AuthPrincipal {
|
|
8
7
|
kind: AuthPrincipalKind;
|
|
@@ -147,3 +146,4 @@ export declare class WandStorage {
|
|
|
147
146
|
private mapSessionRow;
|
|
148
147
|
deleteSession(id: string): void;
|
|
149
148
|
}
|
|
149
|
+
export {};
|
package/dist/storage.js
CHANGED
|
@@ -473,7 +473,7 @@ function mapSessionCore(row) {
|
|
|
473
473
|
function sessionRowQuery(base) {
|
|
474
474
|
return `${base} ${sessionSelectFields()}`;
|
|
475
475
|
}
|
|
476
|
-
|
|
476
|
+
const DEFAULT_DB_FILE = "wand.db";
|
|
477
477
|
export function resolveDatabasePath(configPath) {
|
|
478
478
|
return path.resolve(path.dirname(configPath), DEFAULT_DB_FILE);
|
|
479
479
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StructuredRunnerAdapter, StructuredRunnerContext, StructuredRunnerExecution, StructuredRunnerObserver } from "./structured-runner.js";
|
|
2
2
|
import type { ExecutionMode, SessionSnapshot } from "./types.js";
|
|
3
|
-
|
|
3
|
+
type WandPermissionMode = "default" | "acceptEdits" | "bypassPermissions";
|
|
4
4
|
export interface PermissionPolicy {
|
|
5
5
|
permissionMode: WandPermissionMode;
|
|
6
6
|
allowedTools: string[] | undefined;
|
|
@@ -27,3 +27,4 @@ export declare class ClaudeCliRunner implements StructuredRunnerAdapter {
|
|
|
27
27
|
constructor(options?: ClaudeCliRunnerOptions);
|
|
28
28
|
start(context: StructuredRunnerContext, observer: StructuredRunnerObserver): StructuredRunnerExecution;
|
|
29
29
|
}
|
|
30
|
+
export {};
|
|
@@ -9,7 +9,6 @@ export declare function tagSubagentBlocks(blocks: ContentBlock[], parentToolUseI
|
|
|
9
9
|
export declare function stampSelfTask(blocks: ContentBlock[], registry: TaskMetaMap): ContentBlock[];
|
|
10
10
|
export declare function stampParentTaskResults(blocks: ContentBlock[], registry: TaskMetaMap): ContentBlock[];
|
|
11
11
|
export declare function normalizeClaudeToolInput(name: unknown, input: unknown): Record<string, unknown>;
|
|
12
|
-
export declare function extractClaudeUsage(source: Record<string, unknown> | undefined): ConversationTurn["usage"];
|
|
13
12
|
export declare function extractClaudeModelName(modelUsage: Record<string, unknown> | undefined): string | undefined;
|
|
14
13
|
export declare function extractClaudeAssistantMessage(message: Record<string, unknown>): {
|
|
15
14
|
content: ContentBlock[];
|
|
@@ -77,7 +77,7 @@ export function normalizeClaudeToolInput(name, input) {
|
|
|
77
77
|
}
|
|
78
78
|
return record;
|
|
79
79
|
}
|
|
80
|
-
|
|
80
|
+
function extractClaudeUsage(source) {
|
|
81
81
|
if (!source || !source.usage || typeof source.usage !== "object")
|
|
82
82
|
return undefined;
|
|
83
83
|
const usage = source.usage;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ContentBlock, SessionSnapshot } from "./types.js";
|
|
2
2
|
import type { StructuredRunnerTurnState } from "./structured-runner.js";
|
|
3
3
|
export declare function buildCodexPatchApplyBlocks(item: Record<string, unknown>): ContentBlock[];
|
|
4
|
-
|
|
4
|
+
interface CodexFileSnapshot {
|
|
5
5
|
exists: boolean;
|
|
6
6
|
text: string | null;
|
|
7
7
|
unavailableReason?: string;
|
|
@@ -3,7 +3,6 @@ import type { StructuredRunnerAdapter, StructuredRunnerContext, StructuredRunner
|
|
|
3
3
|
import type { SessionSnapshot } from "./types.js";
|
|
4
4
|
export type OpenCodeTurnState = StructuredRunnerTurnState;
|
|
5
5
|
export declare function buildOpenCodeArgs(session: SessionSnapshot): string[];
|
|
6
|
-
export declare function openCodeToolName(name: string): string;
|
|
7
6
|
/** Apply one OpenCode NDJSON event to the current transport-neutral turn state. */
|
|
8
7
|
export declare function applyOpenCodeEvent(turnState: OpenCodeTurnState, event: Record<string, unknown>, createId?: () => string): string | null;
|
|
9
8
|
/** Production adapter for the external `opencode run --format json` process. */
|
|
@@ -4,7 +4,6 @@ import { SessionLogger } from "./session-logger.js";
|
|
|
4
4
|
import { WandStorage } from "./storage.js";
|
|
5
5
|
import { ExecutionMode, ProcessEvent, SessionProvider, SessionRunner, SessionSnapshot, SessionSource, WandConfig } from "./types.js";
|
|
6
6
|
import type { StructuredRunnerAdapter } from "./structured-runner.js";
|
|
7
|
-
export { isStructuredRunnerForProvider, normalizeThinkingEffort, resolveStructuredRunner, thinkingEffortToClaudeCliEffort, thinkingEffortToCodexReasoningEffort, thinkingEffortToOpenCodeVariant, thinkingEffortToSdkBudget, } from "./structured-provider-common.js";
|
|
8
7
|
export interface StructuredSessionManagerRunners {
|
|
9
8
|
claudeCli?: StructuredRunnerAdapter;
|
|
10
9
|
codex?: StructuredRunnerAdapter;
|
|
@@ -227,3 +226,4 @@ export declare class StructuredSessionManager {
|
|
|
227
226
|
/** Extract usage from an SDKResultSuccess message (sdk runner). */
|
|
228
227
|
private extractSdkUsage;
|
|
229
228
|
}
|
|
229
|
+
export {};
|
|
@@ -18,7 +18,6 @@ import { QoderRunner } from "./structured-qoder-adapter.js";
|
|
|
18
18
|
import { PiRunner } from "./structured-pi-adapter.js";
|
|
19
19
|
import { defaultStructuredRunner, defaultStructuredState, isStructuredRunnerForProvider, normalizeThinkingEffort, resolveStructuredRunner, } from "./structured-provider-common.js";
|
|
20
20
|
import { enrichStructuredMessages, WAND_PROTOCOL_VERSION } from "./structured-client-protocol.js";
|
|
21
|
-
export { isStructuredRunnerForProvider, normalizeThinkingEffort, resolveStructuredRunner, thinkingEffortToClaudeCliEffort, thinkingEffortToCodexReasoningEffort, thinkingEffortToOpenCodeVariant, thinkingEffortToSdkBudget, } from "./structured-provider-common.js";
|
|
22
21
|
/** The runner already persisted/emitted its detailed terminal snapshot. */
|
|
23
22
|
class PersistedStructuredRunnerError extends Error {
|
|
24
23
|
constructor(message) {
|
package/dist/system-ai.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import type { SessionProvider, SystemAiConfig } from "./types.js";
|
|
2
|
-
export declare class SystemAiError extends Error {
|
|
3
|
-
readonly code: string;
|
|
4
|
-
constructor(message: string, code: string);
|
|
5
|
-
}
|
|
6
2
|
export declare function normalizeSystemAiConfig(value: unknown, fallback?: SystemAiConfig): SystemAiConfig;
|
|
7
3
|
/** Copy every usable direct-API profile from the user's configured CLIs. */
|
|
8
4
|
export declare function discoverCliSystemAiConfigs(preferred?: SessionProvider, home?: string): SystemAiConfig[];
|
package/dist/system-ai.js
CHANGED
|
@@ -4,7 +4,7 @@ import os from "node:os";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
const SYSTEM_AI_TIMEOUT_MS = 60_000;
|
|
6
6
|
const SYSTEM_AI_ROUTE_ID_PATTERN = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
7
|
-
|
|
7
|
+
class SystemAiError extends Error {
|
|
8
8
|
code;
|
|
9
9
|
constructor(message, code) {
|
|
10
10
|
super(message);
|
|
@@ -25,7 +25,3 @@ export function terminalDaemonPaths(configPath) {
|
|
|
25
25
|
pidPath: path.join(dir, `.terminald-${suffix}.pid`),
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
-
export function terminalDaemonRuntimeLabel(configPath) {
|
|
29
|
-
const suffix = createHash("sha256").update(path.resolve(configPath)).digest("hex").slice(0, 8);
|
|
30
|
-
return `wand-terminald-${os.userInfo().uid}-${suffix}`;
|
|
31
|
-
}
|
package/dist/tui/commands.d.ts
CHANGED
|
@@ -50,7 +50,6 @@ export declare function copyToClipboard(text: string): CommandResult;
|
|
|
50
50
|
* 默认 system。
|
|
51
51
|
*/
|
|
52
52
|
export type ServiceScope = "system" | "user";
|
|
53
|
-
export declare const DEFAULT_SERVICE_SCOPE: ServiceScope;
|
|
54
53
|
export interface ServiceContext {
|
|
55
54
|
configPath: string;
|
|
56
55
|
/** wand 可执行文件路径。优先使用 process.argv[1],回退到 which wand。 */
|
package/dist/tui/commands.js
CHANGED
|
@@ -149,7 +149,7 @@ function clipboardCandidates() {
|
|
|
149
149
|
// ─── 系统服务(systemd system / user / launchd) ─────────────────────────
|
|
150
150
|
const LAUNCHD_LABEL = "com.wand.web";
|
|
151
151
|
const LAUNCHD_TERMINAL_LABEL = "com.wand.terminald";
|
|
152
|
-
|
|
152
|
+
const DEFAULT_SERVICE_SCOPE = "system";
|
|
153
153
|
/** 当前 process 是不是 root(POSIX)。Windows 永远返回 false。 */
|
|
154
154
|
function isRoot() {
|
|
155
155
|
const fn = process.getuid;
|
package/dist/tui/index.d.ts
CHANGED
|
@@ -16,9 +16,10 @@ export interface TuiDeps {
|
|
|
16
16
|
/** 退出 TUI 时调用。返回的 Promise resolve 后 cli 才会 process.exit。 */
|
|
17
17
|
onExit: (reason: ExitReason) => void | Promise<void>;
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
type ExitReason = "user" | "signal" | "error";
|
|
20
20
|
export interface TuiHandle {
|
|
21
21
|
isActive: boolean;
|
|
22
22
|
stop(reason: ExitReason): Promise<void>;
|
|
23
23
|
}
|
|
24
24
|
export declare function startTui(deps: TuiDeps): TuiHandle;
|
|
25
|
+
export {};
|