@co0ontty/wand 1.75.7 → 2.0.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.
@@ -1,6 +1,6 @@
1
1
  {
2
- "commit": "7ae7673cfd6236680dba087cbd52c1ddbf1e5d65",
3
- "builtAt": "2026-06-26T11:17:58.046Z",
4
- "version": "1.75.7",
2
+ "commit": "77a39200ebf0d88b0048856c3eeb12a00b4dd2b2",
3
+ "builtAt": "2026-06-27T08:59:08.623Z",
4
+ "version": "2.0.0",
5
5
  "channel": "stable"
6
6
  }
@@ -3,7 +3,7 @@ import { spawn } from "node:child_process";
3
3
  import { ClaudeRunError, runClaudePrint } from "./claude-sdk-runner.js";
4
4
  import { buildChildEnv } from "./env-utils.js";
5
5
  import { runGit as runGitBase, runGitRaw as runGitRawBase, getGitErrorMessage } from "./git-utils.js";
6
- import { applyThinkingEffortToPrompt, thinkingEffortToCodexReasoningEffort } from "./structured-session-manager.js";
6
+ import { thinkingEffortToClaudeCliEffort, thinkingEffortToCodexReasoningEffort } from "./structured-session-manager.js";
7
7
  const GIT_TIMEOUT_MS = 1500;
8
8
  const GIT_PUSH_TIMEOUT_MS = 30_000;
9
9
  const MAX_FILE_ENTRIES = 200;
@@ -957,9 +957,11 @@ async function runQuickCommitFallbackCli(opts, priorError) {
957
957
  const model = opts.model?.trim();
958
958
  if (model && model !== "default")
959
959
  args.push("--model", model);
960
+ const claudeEffort = thinkingEffortToClaudeCliEffort(opts.thinkingEffort ?? "off");
961
+ if (claudeEffort)
962
+ args.push("--effort", claudeEffort);
960
963
  args.push("--permission-mode", "bypassPermissions");
961
- const effectivePrompt = applyThinkingEffortToPrompt(prompt, opts.thinkingEffort ?? "off");
962
- await runCliText("claude", args, effectivePrompt, {
964
+ await runCliText("claude", args, prompt, {
963
965
  cwd: opts.cwd,
964
966
  timeoutMs: QUICK_COMMIT_CLI_TIMEOUT_MS,
965
967
  inheritEnv: opts.inheritEnv,
@@ -92,9 +92,8 @@ export declare class ProcessManager extends EventEmitter {
92
92
  */
93
93
  setSessionModel(id: string, model: string | null): SessionSnapshot;
94
94
  /**
95
- * Set the thinking-effort level for a PTY session. For interactive Claude PTY
96
- * we don't intercept raw key input; the effort is applied only when wand UI
97
- * sends a chat-view message (see sendInput → applyThinkingEffortToPrompt).
95
+ * Set the thinking-effort level for a PTY session. Interactive Claude supports
96
+ * this through /effort; off maps to auto, which restores the model default.
98
97
  */
99
98
  setSessionThinkingEffort(id: string, effort: SessionSnapshot["thinkingEffort"]): SessionSnapshot;
100
99
  /**
@@ -14,7 +14,7 @@ import { ensureNodePtyHelperExecutable } from "./ensure-node-pty-helper.js";
14
14
  import { buildLanguageDirective, buildManagedAutonomyDirective } from "./language-prompt.js";
15
15
  import { prepareSessionWorktree } from "./git-worktree.js";
16
16
  import { getCodexResumeCommandSessionId, getResumeCommandSessionId } from "./resume-policy.js";
17
- import { applyThinkingEffortToPrompt, normalizeThinkingEffort } from "./structured-session-manager.js";
17
+ import { normalizeThinkingEffort, thinkingEffortToClaudeCliEffort, thinkingEffortToClaudeSlashEffort } from "./structured-session-manager.js";
18
18
  import { generateSessionTopic } from "./session-topic.js";
19
19
  import { getErrorMessage } from "./error-utils.js";
20
20
  import { resolveSessionCwd } from "./session-cwd.js";
@@ -780,7 +780,8 @@ export class ProcessManager extends EventEmitter {
780
780
  const effectiveMode = provider === "codex" ? "full-access" : mode;
781
781
  const isClaudeProvider = provider === "claude";
782
782
  const selectedModel = opts?.model?.trim() || undefined;
783
- const processedCommand = this.processCommandForMode(command, effectiveMode, provider, selectedModel);
783
+ const initialThinkingEffort = normalizeThinkingEffort(opts?.thinkingEffort);
784
+ const processedCommand = this.processCommandForMode(command, effectiveMode, provider, selectedModel, initialThinkingEffort);
784
785
  const resumeCommandSessionId = isClaudeProvider
785
786
  ? getResumeCommandSessionId(processedCommand) ?? getResumeCommandSessionId(command)
786
787
  : null;
@@ -842,7 +843,7 @@ export class ProcessManager extends EventEmitter {
842
843
  codexSessionDiscoveryTimer: null,
843
844
  approvalStats: { tool: 0, command: 0, file: 0, total: 0 },
844
845
  selectedModel: selectedModel ?? null,
845
- thinkingEffort: normalizeThinkingEffort(opts?.thinkingEffort),
846
+ thinkingEffort: initialThinkingEffort,
846
847
  // cols 上限 256:与 @wterm/dom WASM grid 的 maxCols 硬编码一致,
847
848
  // 防止服务端按 >256 cols 让 Claude 用 CSI 绝对列定位写到 wterm 实际
848
849
  // 渲染不到的列上(表现为"内容神奇复制下行")。
@@ -1224,14 +1225,16 @@ export class ProcessManager extends EventEmitter {
1224
1225
  return this.snapshot(record);
1225
1226
  }
1226
1227
  /**
1227
- * Set the thinking-effort level for a PTY session. For interactive Claude PTY
1228
- * we don't intercept raw key input; the effort is applied only when wand UI
1229
- * sends a chat-view message (see sendInput → applyThinkingEffortToPrompt).
1228
+ * Set the thinking-effort level for a PTY session. Interactive Claude supports
1229
+ * this through /effort; off maps to auto, which restores the model default.
1230
1230
  */
1231
1231
  setSessionThinkingEffort(id, effort) {
1232
1232
  const record = this.mustGet(id);
1233
1233
  const normalized = normalizeThinkingEffort(effort);
1234
1234
  record.thinkingEffort = normalized;
1235
+ if (record.provider === "claude" && record.status === "running" && record.ptyProcess) {
1236
+ record.ptyProcess.write(`/effort ${thinkingEffortToClaudeSlashEffort(normalized)}\r`);
1237
+ }
1235
1238
  this.persist(record);
1236
1239
  this.emitEvent({ type: "status", sessionId: id, data: { thinkingEffort: normalized } });
1237
1240
  return this.snapshot(record);
@@ -1280,19 +1283,11 @@ export class ProcessManager extends EventEmitter {
1280
1283
  };
1281
1284
  this.logger.appendShortcutLog(id, shortcutKey, tailLines, ctx);
1282
1285
  }
1283
- // Thinking-depth magic-word injection. Only applied to chat-view submits
1284
- // (terminal direct keystrokes are pass-through). applyThinkingEffortToPrompt
1285
- // is safe on empty / lone-\r chunks (returns input unchanged) and won't
1286
- // double-prefix if the user already wrote the magic word themselves.
1287
- let effectiveInput = input;
1288
- if (view === "chat" && record.thinkingEffort && record.thinkingEffort !== "off") {
1289
- effectiveInput = applyThinkingEffortToPrompt(input, record.thinkingEffort);
1290
- }
1291
1286
  // Track user input via bridge for Chat mode
1292
1287
  if (record.ptyBridge) {
1293
- record.ptyBridge.onUserInput(effectiveInput);
1288
+ record.ptyBridge.onUserInput(input);
1294
1289
  }
1295
- record.ptyProcess.write(effectiveInput);
1290
+ record.ptyProcess.write(input);
1296
1291
  this.persist(record);
1297
1292
  return this.snapshot(record);
1298
1293
  }
@@ -1963,7 +1958,7 @@ export class ProcessManager extends EventEmitter {
1963
1958
  }
1964
1959
  return false;
1965
1960
  }
1966
- processCommandForMode(command, mode, provider, model) {
1961
+ processCommandForMode(command, mode, provider, model, thinkingEffort) {
1967
1962
  if (provider === "codex") {
1968
1963
  let result = command;
1969
1964
  const trimmedModel = model?.trim();
@@ -1987,6 +1982,10 @@ export class ProcessManager extends EventEmitter {
1987
1982
  const escapedModel = trimmedModel.replace(/'/g, "'\\''");
1988
1983
  result += ` --model '${escapedModel}'`;
1989
1984
  }
1985
+ const claudeEffort = thinkingEffortToClaudeCliEffort(thinkingEffort ?? null);
1986
+ if (claudeEffort && !/--effort(?:\s|=|$)/.test(command)) {
1987
+ result += ` --effort ${claudeEffort}`;
1988
+ }
1990
1989
  const hasPermFlag = /--permission-mode\s/.test(command);
1991
1990
  if (!hasPermFlag) {
1992
1991
  if (isRunningAsRoot()) {
@@ -269,7 +269,7 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
269
269
  }
270
270
  });
271
271
  // 思考深度切换:与 /model 路由对称。结构化会话立即影响下一条 prompt(CLI/SDK 各自接入
272
- // applyThinkingEffortToPrompt / thinking budget),PTY 会话仅影响通过 chat 视图发送的输入。
272
+ // --effort / thinking budget),PTY 会话通过 /effort 更新当前 Claude 进程。
273
273
  app.post("/api/sessions/:id/thinking-effort", express.json(), (req, res) => {
274
274
  const body = req.body;
275
275
  const raw = typeof body?.thinkingEffort === "string" ? body.thinkingEffort : null;
@@ -27,11 +27,10 @@ interface CreateStructuredSessionOptions {
27
27
  export declare function normalizeThinkingEffort(value: unknown): SessionSnapshot["thinkingEffort"];
28
28
  /** Claude SDK 用:把 thinkingEffort 映射成 `thinking.budget_tokens`。off / 空 → 0(不启用)。 */
29
29
  export declare function thinkingEffortToSdkBudget(effort: SessionSnapshot["thinkingEffort"]): number;
30
- /**
31
- * Claude CLI 用:在 prompt 前注入魔法词,让 claude code 自动识别为思考请求。
32
- * off prompt 不变。
33
- */
34
- export declare function applyThinkingEffortToPrompt(prompt: string, effort: SessionSnapshot["thinkingEffort"]): string;
30
+ /** Claude CLI 用:把 thinkingEffort 映射到 `--effort` / `/effort` 支持的等级。off → 不覆盖默认值。 */
31
+ export declare function thinkingEffortToClaudeCliEffort(effort: SessionSnapshot["thinkingEffort"]): string | null;
32
+ /** Claude PTY slash-command 用:off 表示恢复模型默认 effort。 */
33
+ export declare function thinkingEffortToClaudeSlashEffort(effort: SessionSnapshot["thinkingEffort"]): string;
35
34
  /** Codex CLI 用:把 thinkingEffort 映射到 model_reasoning_effort 配置。off → minimal。 */
36
35
  export declare function thinkingEffortToCodexReasoningEffort(effort: SessionSnapshot["thinkingEffort"]): string | null;
37
36
  export declare class StructuredSessionManager {
@@ -121,8 +120,8 @@ export declare class StructuredSessionManager {
121
120
  setSessionModel(sessionId: string, model: string | null): SessionSnapshot;
122
121
  /**
123
122
  * Update the thinking-effort level for a structured session. Takes effect on
124
- * the next spawn / next message (SDK runner injects `thinking`, CLI runner
125
- * prepends magic words, codex runner overrides `model_reasoning_effort`).
123
+ * the next spawn / next message (SDK runner injects `thinking`, Claude CLI
124
+ * runner passes `--effort`, codex runner overrides `model_reasoning_effort`).
126
125
  */
127
126
  setSessionThinkingEffort(sessionId: string, effort: SessionSnapshot["thinkingEffort"]): SessionSnapshot;
128
127
  /**
@@ -46,36 +46,19 @@ export function thinkingEffortToSdkBudget(effort) {
46
46
  default: return 0;
47
47
  }
48
48
  }
49
- /**
50
- * Claude CLI 用:在 prompt 前注入魔法词,让 claude code 自动识别为思考请求。
51
- * off → 原 prompt 不变。
52
- */
53
- export function applyThinkingEffortToPrompt(prompt, effort) {
54
- const trimmed = prompt.trimStart();
55
- if (!trimmed)
56
- return prompt;
57
- let prefix = "";
49
+ /** Claude CLI 用:把 thinkingEffort 映射到 `--effort` / `/effort` 支持的等级。off → 不覆盖默认值。 */
50
+ export function thinkingEffortToClaudeCliEffort(effort) {
58
51
  switch (effort) {
59
- case "standard":
60
- prefix = "think. ";
61
- break;
62
- case "deep":
63
- prefix = "think hard. ";
64
- break;
65
- case "max":
66
- prefix = "ultrathink. ";
67
- break;
52
+ case "standard": return "low";
53
+ case "deep": return "medium";
54
+ case "max": return "max";
68
55
  case "off":
69
- default: return prompt;
70
- }
71
- // 用户已经手写了相同强度的指令时不重复加,避免把 "ultrathink. ultrathink." 喂给模型。
72
- const lower = trimmed.toLowerCase();
73
- if (lower.startsWith("ultrathink") || lower.startsWith("think hard") || lower.startsWith("think very") || lower.startsWith("think harder")) {
74
- return prompt;
56
+ default: return null;
75
57
  }
76
- if (effort === "standard" && lower.startsWith("think"))
77
- return prompt;
78
- return prefix + trimmed;
58
+ }
59
+ /** Claude PTY slash-command 用:off 表示恢复模型默认 effort。 */
60
+ export function thinkingEffortToClaudeSlashEffort(effort) {
61
+ return thinkingEffortToClaudeCliEffort(effort) ?? "auto";
79
62
  }
80
63
  /** Codex CLI 用:把 thinkingEffort 映射到 model_reasoning_effort 配置。off → minimal。 */
81
64
  export function thinkingEffortToCodexReasoningEffort(effort) {
@@ -893,8 +876,8 @@ export class StructuredSessionManager {
893
876
  }
894
877
  /**
895
878
  * Update the thinking-effort level for a structured session. Takes effect on
896
- * the next spawn / next message (SDK runner injects `thinking`, CLI runner
897
- * prepends magic words, codex runner overrides `model_reasoning_effort`).
879
+ * the next spawn / next message (SDK runner injects `thinking`, Claude CLI
880
+ * runner passes `--effort`, codex runner overrides `model_reasoning_effort`).
898
881
  */
899
882
  setSessionThinkingEffort(sessionId, effort) {
900
883
  const session = this.requireSession(sessionId);
@@ -1490,6 +1473,10 @@ export class StructuredSessionManager {
1490
1473
  if (modelChoice && modelChoice !== "default") {
1491
1474
  args.push("--model", modelChoice);
1492
1475
  }
1476
+ const claudeEffort = thinkingEffortToClaudeCliEffort(session.thinkingEffort);
1477
+ if (claudeEffort) {
1478
+ args.push("--effort", claudeEffort);
1479
+ }
1493
1480
  // 托管模式:禁用 AskUserQuestion,让 agent 自己拍板,不要等用户决策。
1494
1481
  // 非托管模式:保留工具,靠 processLine 检测后主动 kill child 触发"中断+续接"流程。
1495
1482
  const isManaged = session.mode === "managed";
@@ -1504,9 +1491,7 @@ export class StructuredSessionManager {
1504
1491
  // 下一个 flag)。表现为 claude 报 "Input must be provided either through
1505
1492
  // stdin or as a prompt argument when using --print"。
1506
1493
  //
1507
- // 思考深度通过给 prompt 前置魔法词触发(think / think hard / ultrathink)。
1508
- // applyThinkingEffortToPrompt 自身已经做了"用户已写过就不重复加"的保护。
1509
- const effectivePrompt = applyThinkingEffortToPrompt(prompt, session.thinkingEffort);
1494
+ // 思考深度通过 --effort 传给 Claude CLI;prompt 保持用户原文。
1510
1495
  const spawnedAt = new Date().toISOString();
1511
1496
  const child = spawn("claude", args, {
1512
1497
  cwd: session.cwd,
@@ -1519,13 +1504,13 @@ export class StructuredSessionManager {
1519
1504
  pid: child.pid ?? null,
1520
1505
  cwd: session.cwd,
1521
1506
  args,
1522
- prompt: effectivePrompt.slice(0, 2048),
1523
- promptLength: effectivePrompt.length,
1507
+ prompt: prompt.slice(0, 2048),
1508
+ promptLength: prompt.length,
1524
1509
  claudeSessionId: session.claudeSessionId,
1525
1510
  spawnedAt,
1526
1511
  });
1527
1512
  this.pendingChildren.set(sessionId, child);
1528
- child.stdin?.end(effectivePrompt);
1513
+ child.stdin?.end(prompt);
1529
1514
  const turnState = {
1530
1515
  blocks: [],
1531
1516
  result: "",
package/dist/types.d.ts CHANGED
@@ -438,10 +438,10 @@ export interface SessionSnapshot {
438
438
  selectedModel?: string | null;
439
439
  /**
440
440
  * 用户选定的思考深度。
441
- * - off: 不启用思考(SDK: 不传 thinking;CLI: 不插魔法词;Codex: model_reasoning_effort minimal)
442
- * - standard: 标准(SDK: budget 4096;CLI: think;Codex: low)
443
- * - deep: 深度(SDK: budget 16000;CLI: think hard;Codex: medium)
444
- * - max: 最深(SDK: budget 31999;CLI: ultrathink;Codex: high)
441
+ * - off: 不覆盖默认思考深度(SDK: 不传 thinking;Claude CLI: auto/default;Codex: model_reasoning_effort minimal)
442
+ * - standard: 标准(SDK: budget 4096;Claude CLI: low;Codex: low)
443
+ * - deep: 深度(SDK: budget 16000;Claude CLI: medium;Codex: medium)
444
+ * - max: 最深(SDK: budget 31999;Claude CLI: max;Codex: high)
445
445
  */
446
446
  thinkingEffort?: "off" | "standard" | "deep" | "max" | null;
447
447
  /** 当前 PTY 列宽,由最近一次 resize 决定。前端用它来判断本端 fit 是否需要校准。 */