@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.
Files changed (54) hide show
  1. package/dist/build-info.json +3 -3
  2. package/dist/config.d.ts +1 -8
  3. package/dist/config.js +2 -2
  4. package/dist/distribution-manager.d.ts +5 -0
  5. package/dist/distribution-manager.js +13 -0
  6. package/dist/message-truncator.d.ts +0 -15
  7. package/dist/message-truncator.js +2 -2
  8. package/dist/middleware/rate-limit.d.ts +0 -1
  9. package/dist/middleware/rate-limit.js +1 -1
  10. package/dist/mission-types.d.ts +2 -1
  11. package/dist/models.d.ts +6 -5
  12. package/dist/npm-update-utils.d.ts +0 -17
  13. package/dist/npm-update-utils.js +5 -5
  14. package/dist/password-manager.d.ts +2 -5
  15. package/dist/password-manager.js +4 -4
  16. package/dist/pidfile.d.ts +0 -1
  17. package/dist/pidfile.js +1 -1
  18. package/dist/server-session-routes.d.ts +1 -2
  19. package/dist/server-session-routes.js +1 -1
  20. package/dist/server-update-routes.d.ts +2 -0
  21. package/dist/server-update-routes.js +7 -0
  22. package/dist/server.d.ts +2 -1
  23. package/dist/session-transport.d.ts +2 -1
  24. package/dist/storage.d.ts +2 -2
  25. package/dist/storage.js +1 -1
  26. package/dist/structured-claude-adapter.d.ts +2 -1
  27. package/dist/structured-claude-protocol.d.ts +0 -1
  28. package/dist/structured-claude-protocol.js +1 -1
  29. package/dist/structured-codex-protocol.d.ts +1 -1
  30. package/dist/structured-opencode-adapter.d.ts +0 -1
  31. package/dist/structured-opencode-adapter.js +1 -1
  32. package/dist/structured-session-manager.d.ts +1 -1
  33. package/dist/structured-session-manager.js +0 -1
  34. package/dist/system-ai.d.ts +0 -4
  35. package/dist/system-ai.js +1 -1
  36. package/dist/terminal-daemon-protocol.d.ts +0 -1
  37. package/dist/terminal-daemon-protocol.js +0 -4
  38. package/dist/tui/commands.d.ts +0 -1
  39. package/dist/tui/commands.js +1 -1
  40. package/dist/tui/index.d.ts +2 -1
  41. package/dist/tui/layout.d.ts +4 -3
  42. package/dist/tui/session-formatter.d.ts +0 -2
  43. package/dist/tui/session-formatter.js +1 -1
  44. package/dist/types.d.ts +17 -20
  45. package/dist/version-utils.d.ts +0 -2
  46. package/dist/version-utils.js +1 -1
  47. package/dist/web-ui/content/scripts.js +1 -1
  48. package/dist/web-ui/embedded-assets.d.ts +1 -1
  49. package/dist/web-ui/embedded-assets.js +2 -2
  50. package/dist/web-ui/index.d.ts +0 -2
  51. package/dist/web-ui/index.js +1 -1
  52. package/dist/workspace-binding.d.ts +0 -1
  53. package/dist/workspace-binding.js +1 -1
  54. package/package.json +1 -6
@@ -1,6 +1,6 @@
1
1
  {
2
- "commit": "6788c46769838380333c0a8ff36fa192041ebae3",
3
- "builtAt": "2026-08-22T04:51:22.312Z",
4
- "version": "4.45.0",
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 { CardExpandDefaults, ExecutionMode, SessionProvider, WandConfig } from "./types.js";
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
- export function migrateLegacyPreferencesToDb(rawJsonInput, storage) {
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
- export function normalizeCardDefaults(input) {
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
- export const MESSAGE_WINDOW_SIZE = 40;
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
- export const MESSAGE_BLOCK_WINDOW = 60;
22
+ const MESSAGE_BLOCK_WINDOW = 60;
23
23
  /**
24
24
  * 块级窗口:取完整历史「最近 blockBudget 个内容块」并做 transport 截断。
25
25
  * 从最新 turn 往回累计块数,能整条放下就整条放,放不下的那条(最旧的入窗 turn)
@@ -5,4 +5,3 @@
5
5
  export declare function checkRateLimit(ip: string): boolean;
6
6
  export declare function recordFailedLogin(ip: string): void;
7
7
  export declare function resetRateLimit(ip: string): void;
8
- export declare function cleanupRateLimiter(): void;
@@ -25,7 +25,7 @@ export function recordFailedLogin(ip) {
25
25
  export function resetRateLimit(ip) {
26
26
  loginAttempts.delete(ip);
27
27
  }
28
- export function cleanupRateLimiter() {
28
+ function cleanupRateLimiter() {
29
29
  const now = Date.now();
30
30
  for (const [ip, record] of loginAttempts.entries()) {
31
31
  if (now > record.resetAt) {
@@ -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
- export interface MissionWorktreeOptions {
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
- export interface ModelCacheStorage {
8
+ interface ModelCacheStorage {
9
9
  getConfigValue(key: string): string | null;
10
10
  setConfigValue(key: string, value: string): void;
11
11
  }
12
- export interface ModelCommandOptions {
12
+ interface ModelCommandOptions {
13
13
  env: NodeJS.ProcessEnv;
14
14
  timeout: number;
15
15
  }
16
- export interface ModelCommandResult {
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
- export interface ClaudeModelsApiEntry {
21
+ interface ClaudeModelsApiEntry {
22
22
  id: string;
23
23
  display_name?: string;
24
24
  }
25
- export interface ClaudeModelsApi {
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,
@@ -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
- export const PACKAGE_NAME = "@co0ontty/wand";
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
- export function getUpdateDistTag(channel) {
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
- export function getStableTagVersion(version) {
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
- export function getNpmGlobalRoot() {
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
- export function cleanupNpmLeftovers() {
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
- export interface PasswordIssue {
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 declare function decodeTotpSecret(secret: string): Buffer;
83
+ export {};
@@ -59,7 +59,7 @@ export function normalizePasswordItemInput(input) {
59
59
  favorite: input.favorite === true,
60
60
  };
61
61
  }
62
- export function normalizeUrls(urls) {
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
- export function normalizeStoredUrl(value) {
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
- export function urlsMatch(storedUrl, pageUrl) {
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
- export function decodeTotpSecret(secret) {
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
- export function pidfilePath(configPath) {
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
- export type SessionListPageEntry = {
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
- export function buildSessionListEntries(sessions) {
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
- export interface ServerUrl {
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
- export type SessionBaseDTO = Omit<SessionSnapshot, "output" | "messages" | "title" | "ptyOutputSeq" | "ptyLaunchMarkerToken"> & {
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
- export declare const DEFAULT_DB_FILE = "wand.db";
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
- export const DEFAULT_DB_FILE = "wand.db";
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
- export type WandPermissionMode = "default" | "acceptEdits" | "bypassPermissions";
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
- export function extractClaudeUsage(source) {
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
- export interface CodexFileSnapshot {
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. */
@@ -39,7 +39,7 @@ export function buildOpenCodeArgs(session) {
39
39
  args.push("--session", session.claudeSessionId);
40
40
  return args;
41
41
  }
42
- export function openCodeToolName(name) {
42
+ function openCodeToolName(name) {
43
43
  const mapped = {
44
44
  bash: "Bash",
45
45
  shell: "Bash",
@@ -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) {
@@ -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
- export class SystemAiError extends Error {
7
+ class SystemAiError extends Error {
8
8
  code;
9
9
  constructor(message, code) {
10
10
  super(message);
@@ -42,4 +42,3 @@ export interface TerminalDaemonAttachPayload {
42
42
  isNew: boolean;
43
43
  }
44
44
  export declare function terminalDaemonPaths(configPath: string): TerminalDaemonPaths;
45
- export declare function terminalDaemonRuntimeLabel(configPath: string): string;
@@ -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
- }
@@ -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。 */
@@ -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
- export const DEFAULT_SERVICE_SCOPE = "system";
152
+ const DEFAULT_SERVICE_SCOPE = "system";
153
153
  /** 当前 process 是不是 root(POSIX)。Windows 永远返回 false。 */
154
154
  function isRoot() {
155
155
  const fn = process.getuid;
@@ -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
- export type ExitReason = "user" | "signal" | "error";
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 {};