@co0ontty/wand 1.21.9 → 1.21.10
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/config.d.ts +1 -1
- package/dist/config.js +13 -0
- package/dist/env-utils.d.ts +9 -0
- package/dist/env-utils.js +47 -0
- package/dist/process-manager.js +3 -3
- package/dist/structured-session-manager.js +3 -2
- package/dist/types.d.ts +6 -0
- package/dist/web-ui/content/scripts.js +14 -0
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { WandStorage } from "./storage.js";
|
|
|
7
7
|
* 升级路径:老 JSON 里仍存有这些字段时,首次启动会被搬到 DB(见 migrateLegacyPreferencesToDb),
|
|
8
8
|
* 然后下一次 saveConfig 写回 JSON 时它们会被剥离(见 stripPreferenceFields)。
|
|
9
9
|
*/
|
|
10
|
-
export declare const PREFERENCE_KEYS: readonly ["defaultMode", "defaultCwd", "defaultModel", "structuredRunner", "language", "cardDefaults"];
|
|
10
|
+
export declare const PREFERENCE_KEYS: readonly ["defaultMode", "defaultCwd", "defaultModel", "structuredRunner", "language", "cardDefaults", "inheritEnv"];
|
|
11
11
|
export type PreferenceKey = (typeof PREFERENCE_KEYS)[number];
|
|
12
12
|
export declare function isPreferenceKey(key: string): key is PreferenceKey;
|
|
13
13
|
export declare const defaultConfig: () => WandConfig;
|
package/dist/config.js
CHANGED
|
@@ -19,6 +19,7 @@ export const PREFERENCE_KEYS = [
|
|
|
19
19
|
"structuredRunner",
|
|
20
20
|
"language",
|
|
21
21
|
"cardDefaults",
|
|
22
|
+
"inheritEnv",
|
|
22
23
|
];
|
|
23
24
|
const PREFERENCE_KEY_SET = new Set(PREFERENCE_KEYS);
|
|
24
25
|
function preferenceStorageKey(key) {
|
|
@@ -43,6 +44,7 @@ export const defaultConfig = () => ({
|
|
|
43
44
|
cardDefaults: defaultCardExpandDefaults(),
|
|
44
45
|
defaultModel: "",
|
|
45
46
|
structuredRunner: "cli",
|
|
47
|
+
inheritEnv: true,
|
|
46
48
|
commandPresets: [
|
|
47
49
|
{
|
|
48
50
|
label: "Claude",
|
|
@@ -201,6 +203,10 @@ export function applyStoragePreferences(config, storage) {
|
|
|
201
203
|
const v = storage.getPreference(preferenceStorageKey("cardDefaults"), defaults.cardDefaults);
|
|
202
204
|
config.cardDefaults = normalizeCardDefaults(v);
|
|
203
205
|
}
|
|
206
|
+
if (storage.hasPreference(preferenceStorageKey("inheritEnv"))) {
|
|
207
|
+
const v = storage.getPreference(preferenceStorageKey("inheritEnv"), defaults.inheritEnv ?? true);
|
|
208
|
+
config.inheritEnv = v === false ? false : true;
|
|
209
|
+
}
|
|
204
210
|
return config;
|
|
205
211
|
}
|
|
206
212
|
/** Write a single preference value to DB and (in-place) update the live config object. */
|
|
@@ -244,6 +250,12 @@ export function writePreferenceToStorage(config, storage, key, value) {
|
|
|
244
250
|
config.cardDefaults = normalized;
|
|
245
251
|
break;
|
|
246
252
|
}
|
|
253
|
+
case "inheritEnv": {
|
|
254
|
+
const v = value === false ? false : true;
|
|
255
|
+
storage.setPreference(dbKey, v);
|
|
256
|
+
config.inheritEnv = v;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
247
259
|
}
|
|
248
260
|
}
|
|
249
261
|
function defaultCardExpandDefaults() {
|
|
@@ -349,6 +361,7 @@ function mergeWithDefaults(input) {
|
|
|
349
361
|
cardDefaults: normalizeCardDefaults(input.cardDefaults),
|
|
350
362
|
defaultModel: typeof input.defaultModel === "string" ? input.defaultModel.trim() : defaults.defaultModel,
|
|
351
363
|
structuredRunner: (input.structuredRunner === "sdk" || input.structuredRunner === "cli") ? input.structuredRunner : defaults.structuredRunner,
|
|
364
|
+
inheritEnv: typeof input.inheritEnv === "boolean" ? input.inheritEnv : (defaults.inheritEnv ?? true),
|
|
352
365
|
};
|
|
353
366
|
}
|
|
354
367
|
export function isExecutionMode(value) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 根据 inheritEnv 配置组装子进程的环境变量。
|
|
3
|
+
*
|
|
4
|
+
* - inheritEnv=true(默认):继承父进程全部 env,再合并 extras 覆盖。
|
|
5
|
+
* - inheritEnv=false:仅保留 MINIMAL_ENV_KEYS 中存在的字段,再合并 extras 覆盖。
|
|
6
|
+
*
|
|
7
|
+
* extras 中的 undefined 字段会被剔除(spawn 不允许 env 值为 undefined)。
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildChildEnv(inheritEnv: boolean, extras?: Record<string, string | undefined>): NodeJS.ProcessEnv;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
/**
|
|
3
|
+
* 用于子进程 spawn 时的环境变量白名单(当用户关闭"继承环境变量"时使用)。
|
|
4
|
+
* 仅保留运行 CLI 工具所需的最小集合,避免把 API key、token 等敏感凭据继承到子命令。
|
|
5
|
+
*/
|
|
6
|
+
const MINIMAL_ENV_KEYS = [
|
|
7
|
+
"PATH",
|
|
8
|
+
"HOME",
|
|
9
|
+
"USER",
|
|
10
|
+
"LOGNAME",
|
|
11
|
+
"SHELL",
|
|
12
|
+
"LANG",
|
|
13
|
+
"LC_ALL",
|
|
14
|
+
"LC_CTYPE",
|
|
15
|
+
"TERM",
|
|
16
|
+
"TZ",
|
|
17
|
+
"TMPDIR",
|
|
18
|
+
"TMP",
|
|
19
|
+
"TEMP",
|
|
20
|
+
"PWD",
|
|
21
|
+
];
|
|
22
|
+
/**
|
|
23
|
+
* 根据 inheritEnv 配置组装子进程的环境变量。
|
|
24
|
+
*
|
|
25
|
+
* - inheritEnv=true(默认):继承父进程全部 env,再合并 extras 覆盖。
|
|
26
|
+
* - inheritEnv=false:仅保留 MINIMAL_ENV_KEYS 中存在的字段,再合并 extras 覆盖。
|
|
27
|
+
*
|
|
28
|
+
* extras 中的 undefined 字段会被剔除(spawn 不允许 env 值为 undefined)。
|
|
29
|
+
*/
|
|
30
|
+
export function buildChildEnv(inheritEnv, extras = {}) {
|
|
31
|
+
const base = {};
|
|
32
|
+
if (inheritEnv) {
|
|
33
|
+
Object.assign(base, process.env);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
for (const key of MINIMAL_ENV_KEYS) {
|
|
37
|
+
const v = process.env[key];
|
|
38
|
+
if (typeof v === "string")
|
|
39
|
+
base[key] = v;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const [k, v] of Object.entries(extras)) {
|
|
43
|
+
if (typeof v === "string")
|
|
44
|
+
base[k] = v;
|
|
45
|
+
}
|
|
46
|
+
return base;
|
|
47
|
+
}
|
package/dist/process-manager.js
CHANGED
|
@@ -9,6 +9,7 @@ import { SessionLogger } from "./session-logger.js";
|
|
|
9
9
|
import { ClaudePtyBridge } from "./claude-pty-bridge.js";
|
|
10
10
|
import { truncateMessagesForTransport } from "./message-truncator.js";
|
|
11
11
|
import { appendWindow, hasExplicitConfirmSyntax, hasPermissionActionContext, normalizePromptText, PTY_OUTPUT_MAX_SIZE } from "./pty-text-utils.js";
|
|
12
|
+
import { buildChildEnv } from "./env-utils.js";
|
|
12
13
|
import { prepareSessionWorktree } from "./git-worktree.js";
|
|
13
14
|
import { getResumeCommandSessionId } from "./resume-policy.js";
|
|
14
15
|
function resolveProviderFromCommand(command) {
|
|
@@ -659,12 +660,11 @@ export class ProcessManager extends EventEmitter {
|
|
|
659
660
|
try {
|
|
660
661
|
child = pty.spawn(this.config.shell, shellArgs, {
|
|
661
662
|
cwd: resolvedCwd,
|
|
662
|
-
env: {
|
|
663
|
-
...process.env,
|
|
663
|
+
env: buildChildEnv(this.config.inheritEnv !== false, {
|
|
664
664
|
WAND_MODE: effectiveMode,
|
|
665
665
|
WAND_AUTO_CONFIRM: effectiveMode === "full-access" ? "1" : "0",
|
|
666
666
|
WAND_AUTO_EDIT: effectiveMode === "auto-edit" ? "1" : "0"
|
|
667
|
-
},
|
|
667
|
+
}),
|
|
668
668
|
name: "xterm-color",
|
|
669
669
|
// 使用 record 上由前端协商好的真实尺寸,避免"先 120 列、几百毫秒后再 resize"
|
|
670
670
|
// 期间 Claude/Codex 用错列宽渲染出 \x1b[120G 这类绝对列定位序列。
|
|
@@ -4,6 +4,7 @@ import { createRequire } from "node:module";
|
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
5
|
import { prepareSessionWorktree } from "./git-worktree.js";
|
|
6
6
|
import { truncateMessagesForTransport } from "./message-truncator.js";
|
|
7
|
+
import { buildChildEnv } from "./env-utils.js";
|
|
7
8
|
function defaultStructuredRunner(provider) {
|
|
8
9
|
return provider === "codex" ? "codex-cli-exec" : "claude-cli-print";
|
|
9
10
|
}
|
|
@@ -756,7 +757,7 @@ export class StructuredSessionManager {
|
|
|
756
757
|
const spawnedAt = new Date().toISOString();
|
|
757
758
|
const child = spawn("codex", args, {
|
|
758
759
|
cwd: session.cwd,
|
|
759
|
-
env:
|
|
760
|
+
env: buildChildEnv(this.config.inheritEnv !== false),
|
|
760
761
|
stdio: ["pipe", "pipe", "pipe"],
|
|
761
762
|
});
|
|
762
763
|
this.logger?.appendStructuredSpawn(sessionId, {
|
|
@@ -1085,7 +1086,7 @@ export class StructuredSessionManager {
|
|
|
1085
1086
|
const spawnedAt = new Date().toISOString();
|
|
1086
1087
|
const child = spawn("claude", args, {
|
|
1087
1088
|
cwd: session.cwd,
|
|
1088
|
-
env:
|
|
1089
|
+
env: buildChildEnv(this.config.inheritEnv !== false),
|
|
1089
1090
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1090
1091
|
});
|
|
1091
1092
|
this.logger?.appendStructuredSpawn(sessionId, {
|
package/dist/types.d.ts
CHANGED
|
@@ -93,6 +93,12 @@ export interface WandConfig {
|
|
|
93
93
|
defaultModel?: string;
|
|
94
94
|
/** 结构化会话使用的 runner: "cli"(默认,spawn claude -p)或 "sdk"(@anthropic-ai/claude-agent-sdk)。 */
|
|
95
95
|
structuredRunner?: "cli" | "sdk";
|
|
96
|
+
/**
|
|
97
|
+
* 启动 PTY / 结构化子进程时是否继承父进程的环境变量(process.env)。默认 true。
|
|
98
|
+
* 关闭后子进程仅获得最小可用环境(PATH/HOME/SHELL/LANG/LC_ALL/TERM 等)外加 WAND_* 控制变量,
|
|
99
|
+
* 用于隔离敏感凭据或避免 API key 泄漏到子命令。
|
|
100
|
+
*/
|
|
101
|
+
inheritEnv?: boolean;
|
|
96
102
|
}
|
|
97
103
|
export interface ClaudeModelInfo {
|
|
98
104
|
/** 传给 --model 的值(别名或完整模型 ID) */
|
|
@@ -2142,6 +2142,16 @@
|
|
|
2142
2142
|
'</select>' +
|
|
2143
2143
|
'<p class="field-hint" style="margin-top:4px;">SDK 模式使用官方 Agent SDK 替代 CLI subprocess,接口更整洁,功能等价。保存后对新建会话立即生效。</p>' +
|
|
2144
2144
|
'</div>' +
|
|
2145
|
+
'<div class="settings-toggle-row">' +
|
|
2146
|
+
'<div class="settings-toggle-text">' +
|
|
2147
|
+
'<label class="settings-toggle-title" for="cfg-inherit-env">继承环境变量</label>' +
|
|
2148
|
+
'<span class="settings-toggle-desc">启动 PTY / 结构化子进程时,把当前服务进程的环境变量传给 claude / codex。关闭后子进程仅获得最小可用环境(PATH/HOME/SHELL/LANG/TERM 等),可用于隔离 API key 等敏感凭据。</span>' +
|
|
2149
|
+
'</div>' +
|
|
2150
|
+
'<label class="settings-switch">' +
|
|
2151
|
+
'<input id="cfg-inherit-env" type="checkbox" class="switch-toggle" />' +
|
|
2152
|
+
'<span class="switch-slider"></span>' +
|
|
2153
|
+
'</label>' +
|
|
2154
|
+
'</div>' +
|
|
2145
2155
|
'<div class="field">' +
|
|
2146
2156
|
'<label class="field-label" for="cfg-default-model">默认模型</label>' +
|
|
2147
2157
|
'<div class="settings-row-with-action">' +
|
|
@@ -7539,6 +7549,9 @@
|
|
|
7539
7549
|
var srEl = document.getElementById("cfg-structured-runner");
|
|
7540
7550
|
if (srEl) srEl.value = cfg.structuredRunner || "cli";
|
|
7541
7551
|
|
|
7552
|
+
var inheritEnvEl = document.getElementById("cfg-inherit-env");
|
|
7553
|
+
if (inheritEnvEl) inheritEnvEl.checked = cfg.inheritEnv !== false;
|
|
7554
|
+
|
|
7542
7555
|
// Default model
|
|
7543
7556
|
state.configDefaultModel = cfg.defaultModel || "";
|
|
7544
7557
|
updateSettingsDefaultModelSelect();
|
|
@@ -7598,6 +7611,7 @@
|
|
|
7598
7611
|
language: (document.getElementById("cfg-language") || {}).value || "",
|
|
7599
7612
|
defaultModel: (document.getElementById("cfg-default-model") || {}).value || "",
|
|
7600
7613
|
structuredRunner: (document.getElementById("cfg-structured-runner") || {}).value || "cli",
|
|
7614
|
+
inheritEnv: (document.getElementById("cfg-inherit-env") || {}).checked !== false,
|
|
7601
7615
|
};
|
|
7602
7616
|
|
|
7603
7617
|
var previousDefaultModel = (state.config && state.config.defaultModel) || "";
|