@co0ontty/wand 4.42.1 → 4.43.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.
@@ -0,0 +1,29 @@
1
+ import type { WandStorage } from "./storage.js";
2
+ import type { Workspace, WorkspaceDefaultProvider, WorktreeInfo } from "./types.js";
3
+ /** Normalize a project/session cwd so `/foo/bar/` and `/foo/bar` match. */
4
+ export declare function normalizeProjectCwd(cwd: string | null | undefined): string;
5
+ /**
6
+ * Directory that should own this session in the project list.
7
+ * Worktree sessions belong to the repo root, not `.wand-worktrees/...`.
8
+ */
9
+ export declare function projectCwdForSession(session: {
10
+ cwd?: string | null;
11
+ worktree?: Pick<WorktreeInfo, "repoRoot" | "path"> | null;
12
+ }): string;
13
+ export declare function findWorkspaceByCwd(storage: WandStorage, cwd: string): Workspace | null;
14
+ export declare function defaultWorkspaceNameForCwd(storage: WandStorage, cwd: string): string;
15
+ /** Find the project for this directory, or create one named after the folder. */
16
+ export declare function ensureWorkspaceForCwd(storage: WandStorage, cwd: string, options?: {
17
+ name?: string;
18
+ defaultProvider?: WorkspaceDefaultProvider;
19
+ }): Workspace;
20
+ /**
21
+ * Workspace id to persist on a newly created session.
22
+ * An explicit id wins; otherwise find-or-create the project for `cwd`.
23
+ */
24
+ export declare function resolveWorkspaceIdForNewSession(storage: WandStorage, cwd: string | null | undefined, explicitWorkspaceId?: string | null): string | undefined;
25
+ export declare function attachUnboundSessionsToWorkspace(storage: WandStorage, workspace: Workspace): number;
26
+ export declare function backfillSessionWorkspaces(storage: WandStorage): {
27
+ created: number;
28
+ bound: number;
29
+ };
@@ -0,0 +1,111 @@
1
+ import path from "node:path";
2
+ import { normalizeSessionDirectory } from "./session-directory-tree.js";
3
+ /** Normalize a project/session cwd so `/foo/bar/` and `/foo/bar` match. */
4
+ export function normalizeProjectCwd(cwd) {
5
+ const trimmed = cwd?.trim() ?? "";
6
+ if (!trimmed)
7
+ return "";
8
+ try {
9
+ return normalizeSessionDirectory(path.resolve(trimmed));
10
+ }
11
+ catch {
12
+ return normalizeSessionDirectory(trimmed);
13
+ }
14
+ }
15
+ /**
16
+ * Directory that should own this session in the project list.
17
+ * Worktree sessions belong to the repo root, not `.wand-worktrees/...`.
18
+ */
19
+ export function projectCwdForSession(session) {
20
+ const repoRoot = session.worktree?.repoRoot?.trim();
21
+ if (repoRoot)
22
+ return normalizeProjectCwd(repoRoot);
23
+ const worktreePath = session.worktree?.path?.trim();
24
+ if (worktreePath) {
25
+ const marker = `${path.sep}.wand-worktrees${path.sep}`;
26
+ const index = worktreePath.indexOf(marker);
27
+ if (index > 0)
28
+ return normalizeProjectCwd(worktreePath.slice(0, index));
29
+ }
30
+ return normalizeProjectCwd(session.cwd);
31
+ }
32
+ export function findWorkspaceByCwd(storage, cwd) {
33
+ const normalized = normalizeProjectCwd(cwd);
34
+ if (!normalized)
35
+ return null;
36
+ return storage.listWorkspaces().find((workspace) => normalizeProjectCwd(workspace.cwd) === normalized) ?? null;
37
+ }
38
+ export function defaultWorkspaceNameForCwd(storage, cwd) {
39
+ const normalized = normalizeProjectCwd(cwd);
40
+ if (!normalized)
41
+ return "未命名项目";
42
+ const custom = storage.listSessionDirectoryNames().get(normalized);
43
+ if (custom?.trim())
44
+ return custom.trim();
45
+ const base = path.basename(normalized);
46
+ return base || normalized;
47
+ }
48
+ /** Find the project for this directory, or create one named after the folder. */
49
+ export function ensureWorkspaceForCwd(storage, cwd, options = {}) {
50
+ const normalized = normalizeProjectCwd(cwd);
51
+ if (!normalized)
52
+ throw new Error("项目目录不能为空。");
53
+ const existing = findWorkspaceByCwd(storage, normalized);
54
+ if (existing)
55
+ return existing;
56
+ return storage.createWorkspace({
57
+ name: options.name?.trim() || defaultWorkspaceNameForCwd(storage, normalized),
58
+ cwd: normalized,
59
+ defaultProvider: options.defaultProvider,
60
+ });
61
+ }
62
+ /**
63
+ * Workspace id to persist on a newly created session.
64
+ * An explicit id wins; otherwise find-or-create the project for `cwd`.
65
+ */
66
+ export function resolveWorkspaceIdForNewSession(storage, cwd, explicitWorkspaceId) {
67
+ const explicit = explicitWorkspaceId?.trim();
68
+ if (explicit)
69
+ return explicit;
70
+ const normalized = normalizeProjectCwd(cwd);
71
+ if (!normalized)
72
+ return undefined;
73
+ return ensureWorkspaceForCwd(storage, normalized).id;
74
+ }
75
+ export function attachUnboundSessionsToWorkspace(storage, workspace) {
76
+ const target = normalizeProjectCwd(workspace.cwd);
77
+ if (!target)
78
+ return 0;
79
+ let bound = 0;
80
+ for (const session of storage.listUnboundSessionBindings()) {
81
+ if (projectCwdForSession(session) !== target)
82
+ continue;
83
+ storage.setSessionWorkspaceId(session.id, workspace.id);
84
+ bound += 1;
85
+ }
86
+ return bound;
87
+ }
88
+ export function backfillSessionWorkspaces(storage) {
89
+ let created = 0;
90
+ let bound = 0;
91
+ const known = new Map();
92
+ for (const workspace of storage.listWorkspaces()) {
93
+ const key = normalizeProjectCwd(workspace.cwd);
94
+ if (key && !known.has(key))
95
+ known.set(key, workspace);
96
+ }
97
+ for (const session of storage.listUnboundSessionBindings()) {
98
+ const cwd = projectCwdForSession(session);
99
+ if (!cwd)
100
+ continue;
101
+ let workspace = known.get(cwd);
102
+ if (!workspace) {
103
+ workspace = ensureWorkspaceForCwd(storage, cwd);
104
+ known.set(cwd, workspace);
105
+ created += 1;
106
+ }
107
+ storage.setSessionWorkspaceId(session.id, workspace.id);
108
+ bound += 1;
109
+ }
110
+ return { created, bound };
111
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@co0ontty/wand",
3
- "version": "4.42.1",
3
+ "version": "4.43.0",
4
4
  "description": "A web console for Claude Code, Codex, OpenCode, and other local CLI tools.",
5
5
  "type": "module",
6
6
  "bin": {