screen-manager-tui 1.0.0 → 1.1.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/README.md CHANGED
@@ -17,24 +17,32 @@ SSH 登录后的交互式 GNU Screen 会话管理器。基于 Ink (React for CLI
17
17
 
18
18
  ## 安装
19
19
 
20
+ 推荐通过 npm 全局安装:
21
+
20
22
  ```bash
21
23
  npm install -g screen-manager-tui
22
24
  ```
23
25
 
24
- 或从源码安装:
26
+ 安装后即可使用 `sm` 命令。
27
+
28
+ <details>
29
+ <summary>从源码安装</summary>
25
30
 
26
31
  ```bash
27
- cd ~/sm
32
+ git clone https://github.com/m2kar/sm.git
33
+ cd sm
28
34
  npm install
29
35
  npm run build
30
- sudo npm link
36
+ npm link
31
37
  ```
32
38
 
39
+ </details>
40
+
33
41
  ## 使用
34
42
 
35
43
  ```bash
36
44
  sm # 启动
37
- SM_HOME=/home/zhiqing sm # 指定项目���目录
45
+ SM_HOME=/home/zhiqing sm # 指定项目根目录
38
46
  ```
39
47
 
40
48
  ### 首页
@@ -84,7 +92,7 @@ SM_HOME=/home/zhiqing sm # 指定项目���目录
84
92
 
85
93
  ```
86
94
  SSH 登录 → sm 启动 → 选择/新建会话 → 进入 screen
87
- ��
95
+
88
96
  └──── Ctrl-A D 从 screen 断开 ────────┘
89
97
  按 q → 退出到 Shell
90
98
  ```
@@ -114,6 +122,15 @@ fi
114
122
  - `$STY` — 已在 screen 中则跳过
115
123
  - `$SM_SKIP=1` — 临时跳过 sm
116
124
 
125
+ ## 发版
126
+
127
+ ```bash
128
+ npm version patch # 或 minor / major
129
+ git push && git push --tags
130
+ ```
131
+
132
+ 推送 `v*` tag 后,GitHub Actions 会自动通过 Trusted Publisher 发布到 npm。
133
+
117
134
  ## 技术栈
118
135
 
119
136
  - [Ink 7](https://github.com/vadimdemedes/ink) (React for CLI) + React 19 + TypeScript
@@ -1,20 +1,7 @@
1
- import { readdirSync, readFileSync, writeFileSync, statSync } from 'node:fs';
1
+ import { readFileSync, writeFileSync, statSync } from 'node:fs';
2
2
  import { join, basename, sep } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
- const EXCLUDED_DIRS = new Set([
5
- 'miniconda3',
6
- 'anaconda3',
7
- '.nvm',
8
- '.npm',
9
- '.cache',
10
- '.local',
11
- '.config',
12
- '.oh-my-zsh',
13
- '.claude',
14
- 'node_modules',
15
- '.vscode-server',
16
- '.cursor-server',
17
- ]);
4
+ const MAX_FAVORITES = 10;
18
5
  export function getHome() {
19
6
  return process.env.SM_HOME || homedir();
20
7
  }
@@ -113,13 +100,10 @@ export function shortenPath(fullPath, maxLen) {
113
100
  const result = sep + abbreviated.join(sep) + sep + last;
114
101
  return result.length <= maxLen ? result : last;
115
102
  }
116
- // --- Project directory listing ---
103
+ // --- Project directory listing (favorites only) ---
117
104
  export function getProjectDirs() {
118
- const home = getHome();
119
- const favorites = loadFavorites();
120
- const favPaths = new Set(favorites.map((f) => f.path));
105
+ const favorites = loadFavorites().slice(0, MAX_FAVORITES);
121
106
  const dirs = [];
122
- // Favorites first, sorted by lastUsed (already sorted)
123
107
  for (const fav of favorites) {
124
108
  try {
125
109
  statSync(fav.path);
@@ -129,31 +113,6 @@ export function getProjectDirs() {
129
113
  // skip non-existent
130
114
  }
131
115
  }
132
- // Home subdirectories (excluding favorites)
133
- try {
134
- const entries = readdirSync(home, { withFileTypes: true });
135
- for (const entry of entries) {
136
- if (!entry.isDirectory())
137
- continue;
138
- if (entry.name.startsWith('.'))
139
- continue;
140
- if (EXCLUDED_DIRS.has(entry.name))
141
- continue;
142
- const fullPath = join(home, entry.name);
143
- if (favPaths.has(fullPath))
144
- continue;
145
- try {
146
- statSync(fullPath);
147
- dirs.push({ name: entry.name, path: fullPath });
148
- }
149
- catch {
150
- // skip
151
- }
152
- }
153
- }
154
- catch {
155
- // ignore
156
- }
157
116
  return dirs;
158
117
  }
159
118
  export function touchFavoriteBySessionName(sessionName) {
@@ -4,13 +4,15 @@ export function listSessions() {
4
4
  const result = spawnSync('screen', ['-ls'], { encoding: 'utf-8' });
5
5
  const output = result.stdout || result.stderr || '';
6
6
  const sessions = [];
7
- const regex = /^\t(\d+)\.(.+?)\t\((.+?)\)\t\((\w+)\)/gm;
7
+ // Linux: \t12345.name\t(03/15/2025 10:30:00 AM)\t(Detached)
8
+ // macOS: \t3396.name\t(Detached)
9
+ const regex = /^\t(\d+)\.(.+?)\t(?:\((.+?)\)\t)?\((Attached|Detached|Dead)\)/gm;
8
10
  let match;
9
11
  while ((match = regex.exec(output)) !== null) {
10
12
  sessions.push({
11
13
  pid: parseInt(match[1], 10),
12
14
  name: match[2],
13
- date: match[3],
15
+ date: match[3] || '',
14
16
  status: match[4],
15
17
  });
16
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "screen-manager-tui",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Screen Manager TUI - Interactive GNU Screen session management tool with React-based terminal UI",
5
5
  "type": "module",
6
6
  "bin": {