@co0ontty/wand 4.41.0 → 4.42.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/git-worktree.d.ts +13 -0
- package/dist/git-worktree.js +21 -0
- package/dist/server-workspace-routes.js +3 -16
- package/dist/session-registry.js +13 -0
- package/dist/web-ui/content/scripts.js +69 -69
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/embedded-assets.d.ts +1 -1
- package/dist/web-ui/embedded-assets.js +3 -3
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commit": "
|
|
3
|
-
"builtAt": "2026-08-
|
|
4
|
-
"version": "4.
|
|
2
|
+
"commit": "0b6a7b8718c885c69a15d7ee14bd7383b4271459",
|
|
3
|
+
"builtAt": "2026-08-09T12:57:20.566Z",
|
|
4
|
+
"version": "4.42.0",
|
|
5
5
|
"channel": "stable"
|
|
6
6
|
}
|
package/dist/git-worktree.d.ts
CHANGED
|
@@ -42,6 +42,19 @@ export declare function resolveWorktreeTargetBranchAsync(cwd: string, gitTimeout
|
|
|
42
42
|
/** Async HTTP-facing worktree check; commands remain deliberately serial. */
|
|
43
43
|
export declare function checkSessionWorktreeMergeabilityAsync(options: WorktreeMergeOptions): Promise<WorktreeMergeCheckResult>;
|
|
44
44
|
export declare function cleanupSessionWorktreeAsync(options: WorktreeOperationOptions): Promise<boolean>;
|
|
45
|
+
/**
|
|
46
|
+
* Best-effort synchronous cleanup of a session/task worktree directory and its
|
|
47
|
+
* branch. Uses `--force` + `-D` (mirroring workspace-task deletion): deleting a
|
|
48
|
+
* session means discarding everything tied to it, including any uncommitted
|
|
49
|
+
* work in its isolated worktree. Any failure (already removed, locked, or a
|
|
50
|
+
* missing repo root) is swallowed so a stale or half-cleaned worktree can never
|
|
51
|
+
* block session deletion.
|
|
52
|
+
*/
|
|
53
|
+
export declare function cleanupWorktreeSync(worktree: {
|
|
54
|
+
path: string;
|
|
55
|
+
branch: string;
|
|
56
|
+
repoRoot?: string;
|
|
57
|
+
} | null | undefined): void;
|
|
45
58
|
/** Async HTTP-facing merge with serial, non-cancellable rollback. */
|
|
46
59
|
export declare function mergeSessionWorktreeAsync(options: WorktreeMergeOptions): Promise<WorktreeMergeResult>;
|
|
47
60
|
export declare function prepareSessionWorktree(options: WorktreeSetupOptions): WorktreeSetupResult;
|
package/dist/git-worktree.js
CHANGED
|
@@ -330,6 +330,27 @@ export async function checkSessionWorktreeMergeabilityAsync(options) {
|
|
|
330
330
|
export async function cleanupSessionWorktreeAsync(options) {
|
|
331
331
|
return cleanupMergedWorktreeAsync(await getMainRepoContextAsync(options));
|
|
332
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* Best-effort synchronous cleanup of a session/task worktree directory and its
|
|
335
|
+
* branch. Uses `--force` + `-D` (mirroring workspace-task deletion): deleting a
|
|
336
|
+
* session means discarding everything tied to it, including any uncommitted
|
|
337
|
+
* work in its isolated worktree. Any failure (already removed, locked, or a
|
|
338
|
+
* missing repo root) is swallowed so a stale or half-cleaned worktree can never
|
|
339
|
+
* block session deletion.
|
|
340
|
+
*/
|
|
341
|
+
export function cleanupWorktreeSync(worktree) {
|
|
342
|
+
const repoRoot = worktree?.repoRoot;
|
|
343
|
+
if (!repoRoot)
|
|
344
|
+
return;
|
|
345
|
+
try {
|
|
346
|
+
runGit(["worktree", "remove", "--force", worktree.path], repoRoot);
|
|
347
|
+
}
|
|
348
|
+
catch { /* best effort */ }
|
|
349
|
+
try {
|
|
350
|
+
runGit(["branch", "-D", worktree.branch], repoRoot);
|
|
351
|
+
}
|
|
352
|
+
catch { /* best effort */ }
|
|
353
|
+
}
|
|
333
354
|
/** Async HTTP-facing merge with serial, non-cancellable rollback. */
|
|
334
355
|
export async function mergeSessionWorktreeAsync(options) {
|
|
335
356
|
const context = await getMainRepoContextAsync(options);
|
|
@@ -4,8 +4,7 @@ import { existsSync, statSync } from "node:fs";
|
|
|
4
4
|
import { asyncRoute } from "./express-async.js";
|
|
5
5
|
import { getErrorMessage } from "./error-utils.js";
|
|
6
6
|
import { expandHomePath } from "./middleware/path-safety.js";
|
|
7
|
-
import { checkSessionWorktreeMergeabilityAsync, prepareSessionWorktree, resolveWorktreeTargetBranchAsync, } from "./git-worktree.js";
|
|
8
|
-
import { runGit } from "./git-utils.js";
|
|
7
|
+
import { checkSessionWorktreeMergeabilityAsync, cleanupWorktreeSync, prepareSessionWorktree, resolveWorktreeTargetBranchAsync, } from "./git-worktree.js";
|
|
9
8
|
const PROVIDERS = new Set(["claude", "codex", "opencode", "grok", "qoder", "pi"]);
|
|
10
9
|
function parseDefaultProvider(value) {
|
|
11
10
|
return typeof value === "string" && PROVIDERS.has(value) ? value : undefined;
|
|
@@ -22,18 +21,6 @@ function resolveWorkspaceCwd(raw) {
|
|
|
22
21
|
throw new Error(`不是目录:${resolved}`);
|
|
23
22
|
return resolved;
|
|
24
23
|
}
|
|
25
|
-
function cleanupTaskWorktree(worktree) {
|
|
26
|
-
if (!worktree?.repoRoot)
|
|
27
|
-
return;
|
|
28
|
-
try {
|
|
29
|
-
runGit(["worktree", "remove", "--force", worktree.path], worktree.repoRoot);
|
|
30
|
-
}
|
|
31
|
-
catch { /* best effort */ }
|
|
32
|
-
try {
|
|
33
|
-
runGit(["branch", "-D", worktree.branch], worktree.repoRoot);
|
|
34
|
-
}
|
|
35
|
-
catch { /* best effort */ }
|
|
36
|
-
}
|
|
37
24
|
function deleteSessions(storage, sessions, sessionIds) {
|
|
38
25
|
for (const sessionId of new Set(sessionIds)) {
|
|
39
26
|
if (sessions)
|
|
@@ -252,7 +239,7 @@ export function registerWorkspaceRoutes(app, storage, sessions) {
|
|
|
252
239
|
}
|
|
253
240
|
for (const task of tasks) {
|
|
254
241
|
if (cascade || task.worktree)
|
|
255
|
-
|
|
242
|
+
cleanupWorktreeSync(task.worktree);
|
|
256
243
|
}
|
|
257
244
|
storage.deleteWorkspace(existing.id, { cascade });
|
|
258
245
|
res.json({ ok: true });
|
|
@@ -440,7 +427,7 @@ export function registerWorkspaceRoutes(app, storage, sessions) {
|
|
|
440
427
|
}
|
|
441
428
|
// 尽力清理 worktree 与分支;失败不阻塞删除任务行。
|
|
442
429
|
if (cascade)
|
|
443
|
-
|
|
430
|
+
cleanupWorktreeSync(existing.worktree);
|
|
444
431
|
storage.deleteWorkspaceTask(existing.id, { cascade });
|
|
445
432
|
res.json({ ok: true });
|
|
446
433
|
});
|
package/dist/session-registry.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cleanupWorktreeSync } from "./git-worktree.js";
|
|
1
2
|
function slimSnapshot(snapshot) {
|
|
2
3
|
const { output: _output, messages: _messages, ...slim } = snapshot;
|
|
3
4
|
return { ...slim, output: "" };
|
|
@@ -111,6 +112,18 @@ export class SessionRegistry {
|
|
|
111
112
|
const snapshot = this.get(id);
|
|
112
113
|
if (!snapshot)
|
|
113
114
|
return null;
|
|
115
|
+
// Best-effort: tear down the session's isolated worktree (directory +
|
|
116
|
+
// branch) before removing the session record. Without this, deleting a
|
|
117
|
+
// session that was never merged leaves an orphan under `.wand-worktrees/`
|
|
118
|
+
// and a dangling `wand/*` branch forever — the merge path is the only
|
|
119
|
+
// other place that cleans them up. Force removal is intentional: deleting
|
|
120
|
+
// a session means discarding everything tied to it.
|
|
121
|
+
if (snapshot.worktree) {
|
|
122
|
+
try {
|
|
123
|
+
cleanupWorktreeSync(snapshot.worktree);
|
|
124
|
+
}
|
|
125
|
+
catch { /* never block deletion */ }
|
|
126
|
+
}
|
|
114
127
|
const owner = this.ownerOf(id);
|
|
115
128
|
if (owner === "structured")
|
|
116
129
|
this.structured.delete(id);
|