worktree-flow 0.0.10 → 0.0.12
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/README.md
CHANGED
|
@@ -88,7 +88,7 @@ Remove workspaces interactively. Shows all workspaces with their status (similar
|
|
|
88
88
|
|
|
89
89
|
### `flow tmux resume`
|
|
90
90
|
|
|
91
|
-
Create tmux sessions for all workspaces that don't already have one. Each session is created with split panes (one for the workspace root and one for each worktree) using a tiled layout. Skips workspaces that already have active sessions.
|
|
91
|
+
Create tmux sessions for all workspaces that don't already have one. Each session is created with split panes (one for the workspace root and one for each worktree that matches a repo from source-path) using a tiled layout. Skips workspaces that already have active sessions.
|
|
92
92
|
|
|
93
93
|
Requires `tmux` to be installed and the `tmux` config option to be enabled.
|
|
94
94
|
|
package/dist/lib/git.js
CHANGED
|
@@ -20,12 +20,20 @@ export class GitService {
|
|
|
20
20
|
return output.length > 0;
|
|
21
21
|
}
|
|
22
22
|
async localRemoteBranchExists(repoPath, branch) {
|
|
23
|
+
// Check for local branch first
|
|
23
24
|
try {
|
|
24
|
-
await this.exec(repoPath, ['rev-parse', '--verify',
|
|
25
|
+
await this.exec(repoPath, ['rev-parse', '--verify', branch]);
|
|
25
26
|
return true;
|
|
26
27
|
}
|
|
27
28
|
catch {
|
|
28
|
-
|
|
29
|
+
// Fall back to checking remote-tracking branch
|
|
30
|
+
try {
|
|
31
|
+
await this.exec(repoPath, ['rev-parse', '--verify', `origin/${branch}`]);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
39
|
async findFirstExistingBranch(repoPath, candidates) {
|
|
@@ -44,7 +44,14 @@ export class WorkspaceDirectoryService {
|
|
|
44
44
|
getWorktreeDirs(workspacePath) {
|
|
45
45
|
const entries = this.fs.readdirSync(workspacePath, { withFileTypes: true });
|
|
46
46
|
return entries
|
|
47
|
-
.filter((entry) =>
|
|
47
|
+
.filter((entry) => {
|
|
48
|
+
if (!entry.isDirectory()) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
// Only include directories that have a .git file or directory (git repos/worktrees)
|
|
52
|
+
const gitPath = path.join(workspacePath, entry.name, '.git');
|
|
53
|
+
return this.fs.existsSync(gitPath);
|
|
54
|
+
})
|
|
48
55
|
.map((entry) => path.join(workspacePath, entry.name));
|
|
49
56
|
}
|
|
50
57
|
listWorkspaces(destPath) {
|
|
@@ -1,26 +1,50 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
1
2
|
/**
|
|
2
3
|
* Use case for resuming tmux sessions across all workspaces.
|
|
3
4
|
* Creates sessions for workspaces that don't already have one.
|
|
5
|
+
* Only creates splits for directories that match repos from source-path.
|
|
4
6
|
*/
|
|
5
7
|
export class ResumeTmuxSessionsUseCase {
|
|
6
8
|
workspaceDir;
|
|
7
9
|
tmux;
|
|
8
|
-
|
|
10
|
+
repos;
|
|
11
|
+
config;
|
|
12
|
+
constructor(workspaceDir, tmux, repos, config) {
|
|
9
13
|
this.workspaceDir = workspaceDir;
|
|
10
14
|
this.tmux = tmux;
|
|
15
|
+
this.repos = repos;
|
|
16
|
+
this.config = config;
|
|
11
17
|
}
|
|
12
18
|
async execute(params) {
|
|
13
19
|
// 1. List all workspaces
|
|
14
20
|
const workspaces = this.workspaceDir.listWorkspaces(params.destPath);
|
|
21
|
+
// Early return if no workspaces
|
|
22
|
+
if (workspaces.length === 0) {
|
|
23
|
+
return {
|
|
24
|
+
totalWorkspaces: 0,
|
|
25
|
+
sessionsCreated: 0,
|
|
26
|
+
sessionsSkipped: 0,
|
|
27
|
+
errors: [],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// 2. Get valid repo names from source-path
|
|
31
|
+
const { sourcePath } = this.config.getRequired();
|
|
32
|
+
const repoPaths = this.repos.discoverRepos(sourcePath);
|
|
33
|
+
const validRepoNames = new Set(repoPaths.map(repoPath => path.basename(repoPath)));
|
|
15
34
|
let sessionsCreated = 0;
|
|
16
35
|
let sessionsSkipped = 0;
|
|
17
36
|
const errors = [];
|
|
18
|
-
//
|
|
37
|
+
// 3. Try to create tmux session for each workspace
|
|
19
38
|
for (const workspace of workspaces) {
|
|
20
39
|
try {
|
|
21
|
-
const
|
|
40
|
+
const allWorktreeDirs = this.workspaceDir.getWorktreeDirs(workspace.path);
|
|
41
|
+
// Filter to only include directories that match repo names from source-path
|
|
42
|
+
const filteredWorktreeDirs = allWorktreeDirs.filter(worktreeDir => {
|
|
43
|
+
const dirName = path.basename(worktreeDir);
|
|
44
|
+
return validRepoNames.has(dirName);
|
|
45
|
+
});
|
|
22
46
|
// Try to create session - will throw on duplicate session
|
|
23
|
-
await this.tmux.createSession(workspace.path, workspace.name,
|
|
47
|
+
await this.tmux.createSession(workspace.path, workspace.name, filteredWorktreeDirs);
|
|
24
48
|
sessionsCreated++;
|
|
25
49
|
}
|
|
26
50
|
catch (error) {
|
|
@@ -27,6 +27,6 @@ export function createUseCases(services) {
|
|
|
27
27
|
checkWorkspaceStatus: new CheckWorkspaceStatusUseCase(services.workspaceDir, services.workspaceConfig, services.status),
|
|
28
28
|
discoverPrunableWorkspaces: new DiscoverPrunableWorkspacesUseCase(services.workspaceDir, services.workspaceConfig, services.status, services.git),
|
|
29
29
|
listWorkspacesWithStatus: new ListWorkspacesWithStatusUseCase(services.workspaceDir, services.workspaceConfig, services.status),
|
|
30
|
-
resumeTmuxSessions: new ResumeTmuxSessionsUseCase(services.workspaceDir, services.tmux),
|
|
30
|
+
resumeTmuxSessions: new ResumeTmuxSessionsUseCase(services.workspaceDir, services.tmux, services.repos, services.config),
|
|
31
31
|
};
|
|
32
32
|
}
|