@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.
- package/dist/build-info.json +3 -3
- package/dist/process-manager.js +1 -1
- package/dist/server-session-routes.js +67 -32
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commit": "
|
|
3
|
-
"builtAt": "2026-06-
|
|
4
|
-
"version": "1.
|
|
2
|
+
"commit": "812271c2394f80a00b4feb4c4c2101dae80b7dc9",
|
|
3
|
+
"builtAt": "2026-06-20T00:57:39.527Z",
|
|
4
|
+
"version": "1.75.0",
|
|
5
5
|
"channel": "stable"
|
|
6
6
|
}
|
package/dist/process-manager.js
CHANGED
|
@@ -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
|
|
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
|
}
|