@co0ontty/wand 1.74.2 → 1.75.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": "1d95b24ccff1cb78cacd19f7b873287337745e2f",
3
- "builtAt": "2026-06-19T12:08:31.089Z",
4
- "version": "1.74.2",
2
+ "commit": "812271c2394f80a00b4feb4c4c2101dae80b7dc9",
3
+ "builtAt": "2026-06-20T00:57:39.527Z",
4
+ "version": "1.75.0",
5
5
  "channel": "stable"
6
6
  }
@@ -1009,7 +1009,7 @@ export class ProcessManager extends EventEmitter {
1009
1009
  if (rec.autoApprovePermissions && !rec.ptyBridge && rec.provider === "claude") {
1010
1010
  this.autoConfirmWithRecord(rec, chunk, child);
1011
1011
  }
1012
- if (initialInput && !initialInputSent && chunk.includes("❯")) {
1012
+ if (initialInput && !initialInputSent && (chunk.includes("❯") || chunk.includes("›"))) {
1013
1013
  sendInitialInput();
1014
1014
  }
1015
1015
  this.schedulePersist(rec);
@@ -136,6 +136,65 @@ function buildCodexResumeCommand(command, threadId) {
136
136
  .trim();
137
137
  return `${withoutExistingResume || "codex"} resume ${threadId}`;
138
138
  }
139
+ function resolvePtyResumeProvider(snapshot) {
140
+ const provider = snapshot.provider ?? (/^codex\b/.test(snapshot.command.trim()) ? "codex" : "claude");
141
+ if (provider !== "claude" && provider !== "codex") {
142
+ throw new Error("只有 Claude 或 Codex provider 支持恢复功能。");
143
+ }
144
+ return provider;
145
+ }
146
+ function startResumedPtySession(processes, existingSession, sessionId, defaultMode, body, initialInput) {
147
+ if ((existingSession.sessionKind ?? "pty") !== "pty") {
148
+ throw new Error("结构化会话不支持 PTY resume。");
149
+ }
150
+ const command = existingSession.command.trim();
151
+ const provider = resolvePtyResumeProvider(existingSession);
152
+ const resumeSessionId = existingSession.claudeSessionId;
153
+ if (!resumeSessionId) {
154
+ throw new Error(provider === "codex" ? "此会话没有 Codex thread ID,无法恢复。" : "此会话没有 Claude 会话 ID,无法恢复。");
155
+ }
156
+ if (provider === "claude" && !/^claude\b/.test(command)) {
157
+ throw new Error("只有 Claude 命令支持恢复功能。");
158
+ }
159
+ if (provider === "codex") {
160
+ if (!/^codex\b/.test(command)) {
161
+ throw new Error("只有 Codex 命令支持恢复功能。");
162
+ }
163
+ if (!processes.hasCodexSessionFile(resumeSessionId)) {
164
+ throw new Error("对应的 Codex 历史会话不存在,无法恢复。");
165
+ }
166
+ }
167
+ const newMode = body.mode ? normalizeMode(body.mode, defaultMode) : normalizeMode(existingSession.mode, defaultMode);
168
+ const resumeCommand = provider === "codex"
169
+ ? buildCodexResumeCommand(command, resumeSessionId)
170
+ : `${command} --resume ${resumeSessionId}`;
171
+ const reqCols = typeof body.cols === "number" && Number.isFinite(body.cols) ? body.cols : undefined;
172
+ const reqRows = typeof body.rows === "number" && Number.isFinite(body.rows) ? body.rows : undefined;
173
+ return processes.start(resumeCommand, existingSession.cwd, newMode, initialInput, {
174
+ reuseId: sessionId,
175
+ cols: reqCols,
176
+ rows: reqRows,
177
+ provider,
178
+ model: existingSession.selectedModel ?? undefined,
179
+ thinkingEffort: existingSession.thinkingEffort ?? undefined,
180
+ });
181
+ }
182
+ function getAutoResumeInitialInput(input, view, shortcutKey) {
183
+ if (view === "terminal")
184
+ return null;
185
+ if (shortcutKey && shortcutKey !== "enter_text")
186
+ return null;
187
+ const trimmedRight = input.replace(/[\r\n]+$/g, "").trimEnd();
188
+ return trimmedRight.trim().length > 0 ? trimmedRight : null;
189
+ }
190
+ function canAutoResumePtyForInput(snapshot, input) {
191
+ return Boolean(snapshot
192
+ && (snapshot.sessionKind ?? "pty") === "pty"
193
+ && snapshot.status !== "running"
194
+ && (snapshot.provider === "claude" || snapshot.provider === "codex" || /^codex\b/.test(snapshot.command.trim()) || /^claude\b/.test(snapshot.command.trim()))
195
+ && snapshot.claudeSessionId
196
+ && input);
197
+ }
139
198
  function canMergeSession(snapshot) {
140
199
  return Boolean(snapshot.worktreeEnabled && snapshot.worktree?.branch && snapshot.worktree?.path);
141
200
  }
@@ -722,38 +781,7 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
722
781
  res.status(400).json({ error: "结构化会话不支持 PTY resume。" });
723
782
  return;
724
783
  }
725
- const command = existingSession.command.trim();
726
- const provider = existingSession.provider ?? (/^codex\b/.test(command) ? "codex" : "claude");
727
- if (provider !== "claude" && provider !== "codex") {
728
- res.status(400).json({ error: "只有 Claude 或 Codex provider 支持恢复功能。" });
729
- return;
730
- }
731
- const resumeSessionId = existingSession.claudeSessionId;
732
- if (!resumeSessionId) {
733
- res.status(400).json({ error: provider === "codex" ? "此会话没有 Codex thread ID,无法恢复。" : "此会话没有 Claude 会话 ID,无法恢复。" });
734
- return;
735
- }
736
- if (provider === "claude" && !/^claude\b/.test(command)) {
737
- res.status(400).json({ error: "只有 Claude 命令支持恢复功能。" });
738
- return;
739
- }
740
- if (provider === "codex") {
741
- if (!/^codex\b/.test(command)) {
742
- res.status(400).json({ error: "只有 Codex 命令支持恢复功能。" });
743
- return;
744
- }
745
- if (!processes.hasCodexSessionFile(resumeSessionId)) {
746
- res.status(400).json({ error: "对应的 Codex 历史会话不存在,无法恢复。" });
747
- return;
748
- }
749
- }
750
- const newMode = body.mode ? normalizeMode(body.mode, defaultMode) : normalizeMode(existingSession.mode, defaultMode);
751
- const resumeCommand = provider === "codex"
752
- ? buildCodexResumeCommand(command, resumeSessionId)
753
- : `${command} --resume ${resumeSessionId}`;
754
- const reqCols = typeof body.cols === "number" && Number.isFinite(body.cols) ? body.cols : undefined;
755
- const reqRows = typeof body.rows === "number" && Number.isFinite(body.rows) ? body.rows : undefined;
756
- const newSnapshot = processes.start(resumeCommand, existingSession.cwd, newMode, undefined, { reuseId: sessionId, cols: reqCols, rows: reqRows, provider });
784
+ const newSnapshot = startResumedPtySession(processes, existingSession, sessionId, defaultMode, body);
757
785
  res.status(201).json(newSnapshot);
758
786
  }
759
787
  catch (error) {
@@ -824,6 +852,13 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
824
852
  res.json(snapshot);
825
853
  return;
826
854
  }
855
+ const autoResumeInput = getAutoResumeInitialInput(input, view, shortcutKey);
856
+ const existingSession = processes.get(sessionId) || storage.getSession(sessionId);
857
+ if (autoResumeInput !== null && canAutoResumePtyForInput(existingSession, autoResumeInput)) {
858
+ const snapshot = startResumedPtySession(processes, existingSession, sessionId, defaultMode, {}, autoResumeInput);
859
+ res.json(snapshot);
860
+ return;
861
+ }
827
862
  const snapshot = processes.sendInput(sessionId, input, view, shortcutKey);
828
863
  res.json(snapshot);
829
864
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@co0ontty/wand",
3
- "version": "1.74.2",
3
+ "version": "1.75.0",
4
4
  "description": "A web terminal for local CLI tools like Claude.",
5
5
  "type": "module",
6
6
  "bin": {