vibe-pomo 0.2.1 → 0.2.2

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
@@ -27,6 +27,8 @@ Every session is logged — what the agent did, what you did — giving you a cl
27
27
 
28
28
  **Prerequisites:** Node.js 20+, Claude Code CLI
29
29
 
30
+ **Recommended:** run Claude Code inside `tmux`. That is the primary supported interactive timer experience: vibe-pomo uses a `tmux` popup to cover the current pane during a Pomodoro. Outside `tmux`, sessions still run, but timer UI falls back to headless mode.
31
+
30
32
  ```bash
31
33
  npm i -g vibe-pomo
32
34
  pomodoro install
@@ -71,6 +73,8 @@ pomodoro daemon
71
73
 
72
74
  ### 2. Start a session
73
75
 
76
+ For the intended covered-screen workflow, open Claude Code inside a `tmux` session before running `/pomodoro ...`.
77
+
74
78
  ```bash
75
79
  # From Claude Code (recommended)
76
80
  /pomodoro 25m Refactor the auth module
@@ -80,7 +84,7 @@ pomodoro start 25m Refactor the auth module
80
84
  pomodoro start Refactor the auth module # uses default duration
81
85
  ```
82
86
 
83
- If Claude Code is running inside `tmux`, vibe-pomo opens a popup over the current pane so the ongoing task stays covered until you end or break the session. Outside `tmux`, it falls back to a separate timer terminal.
87
+ If Claude Code is running inside `tmux`, vibe-pomo opens a popup over the current pane so the ongoing task stays covered until you end or break the session. Outside `tmux`, it stays headless: the session still runs, but visualization remains in the daemon dashboard and stats view instead of opening another terminal window.
84
88
 
85
89
  ```
86
90
  🍅 Pomodoro
@@ -163,7 +167,7 @@ Recent Sessions
163
167
  |--------|--------|-------------|
164
168
  | `defaultDurationMs` | ms | Default session duration (25 min = `1500000`) |
165
169
  | `decisionStrategy` | `"wait"` / `"break"` | When the agent is blocked: wait silently until you end the session (default), or end immediately |
166
- | `terminalEmulator` | `"auto"` / `"tmux"` / `"tmux-window"` / name | Timer surface. `"tmux"` opens a popup overlay, `"tmux-window"` uses a new tmux window, and `"auto"` prefers the popup when `$TMUX` is set. |
170
+ | `terminalEmulator` | `"auto"` / `"tmux"` / `"none"` | Timer surface. `"tmux"` opens a popup overlay, `"none"` forces headless mode, and `"auto"` uses the popup only when `$TMUX` is set. |
167
171
  | `soundOnOvertime` | bool | Play a sound when the timer hits zero |
168
172
 
169
173
  ---
package/README.zh.md CHANGED
@@ -84,6 +84,8 @@ What did you do during this session?
84
84
 
85
85
  **前置条件:** Node.js 20+、Claude Code CLI
86
86
 
87
+ **推荐条件:** 请在 `tmux` 里运行 Claude Code。这是 vibe-pomo 当前主推的交互方式:番茄钟会通过 `tmux popup` 覆盖当前 pane。非 `tmux` 环境下,会话仍然会正常运行,但计时器 UI 会退化为无界面模式。
88
+
87
89
  ```bash
88
90
  npm install -g vibe-pomo
89
91
  pomodoro install
@@ -111,6 +113,8 @@ pomodoro daemon
111
113
 
112
114
  ### 2. 开始一个会话
113
115
 
116
+ 如果你希望获得“盖住当前 Claude Code 窗口”的预期体验,请先在 `tmux` session 里打开 Claude Code,再执行 `/pomodoro ...`。
117
+
114
118
  ```bash
115
119
  # 在 Claude Code 中(推荐)
116
120
  /pomodoro 25m Refactor the auth module
@@ -120,7 +124,7 @@ pomodoro start 25m Refactor the auth module
120
124
  pomodoro start Refactor the auth module # 使用默认时长
121
125
  ```
122
126
 
123
- 如果 Claude Code 跑在 `tmux` 里,vibe-pomo 会在当前 pane 上弹出一个覆盖式 popup,把正在进行的任务界面盖住,直到你结束或中断番茄钟。非 `tmux` 环境下则回退到单独的计时器终端窗口。
127
+ 如果 Claude Code 跑在 `tmux` 里,vibe-pomo 会在当前 pane 上弹出一个覆盖式 popup,把正在进行的任务界面盖住,直到你结束或中断番茄钟。非 `tmux` 环境下则保持无界面模式:会话照常运行,但只通过 daemon 仪表板和统计视图展示,不再额外弹出终端窗口。
124
128
 
125
129
  ### 3. 会话进行中
126
130
 
@@ -177,7 +181,7 @@ Recent Sessions
177
181
  |------|------|------|
178
182
  | `defaultDurationMs` | 毫秒数 | 默认会话时长(25 分钟 = `1500000`) |
179
183
  | `decisionStrategy` | `"wait"` / `"break"` | 代理被阻塞时的策略:静默等待直到你结束会话(默认),或立即结束 |
180
- | `terminalEmulator` | `"auto"` / `"tmux"` / `"tmux-window"` / 名称 | 计时器展示方式。`"tmux"` 打开覆盖式 popup,`"tmux-window"` 使用新的 tmux window,`"auto"` 在检测到 `$TMUX` 时优先使用 popup |
184
+ | `terminalEmulator` | `"auto"` / `"tmux"` / `"none"` | 计时器展示方式。`"tmux"` 打开覆盖式 popup,`"none"` 强制无界面模式,`"auto"` 仅在检测到 `$TMUX` 时使用 popup |
181
185
  | `soundOnOvertime` | 布尔值 | 计时归零时播放提示音 |
182
186
 
183
187
  ---
package/bin/pomodoro.mjs CHANGED
@@ -109,20 +109,16 @@ async function cmdStart(args) {
109
109
  spawnWatcher(resp.sessionId)
110
110
  }
111
111
 
112
- // Launch timer TUI in a new terminal window
112
+ // Only launch an interactive timer UI when we can safely cover the current
113
+ // Claude Code pane with a tmux popup. Otherwise stay headless and let the
114
+ // daemon/dashboard own visualization so the conversation flow is not disturbed.
113
115
  const timerEntry = join(ROOT, 'src', 'tui', 'timer', 'index.tsx')
114
- const launched = await launchTerminal({
116
+ await launchTerminal({
115
117
  tsx: TSX,
116
118
  entryFile: timerEntry,
117
119
  sessionId: resp.sessionId,
118
120
  termPref: config.terminalEmulator,
119
121
  })
120
-
121
- if (!launched) {
122
- console.log(`POMODORO_TIMER_NOT_LAUNCHED`)
123
- console.log(` To watch the timer: node ${TSX} ${timerEntry} ${resp.sessionId}`)
124
- console.log(` To end the session: node ${join(ROOT, 'bin', 'pomodoro.mjs')} stop`)
125
- }
126
122
  }
127
123
 
128
124
  async function cmdStop(args) {
@@ -187,52 +183,23 @@ async function cmdStopDaemon() {
187
183
  // ── Terminal launch helpers ───────────────────────────────────────────────────
188
184
 
189
185
  async function launchTerminal({ tsx, entryFile, sessionId, termPref }) {
190
- const terminals = termPref && termPref !== 'auto'
191
- ? [termPref]
192
- : detectTerminals()
193
-
194
- for (const term of terminals) {
195
- const ok = await trySpawn(term, tsx, entryFile, sessionId)
196
- if (ok) return true
197
- }
198
- return false
186
+ const mode = resolveTimerMode(termPref)
187
+ if (mode !== 'tmux-popup') return false
188
+ return trySpawn(mode, tsx, entryFile, sessionId)
199
189
  }
200
190
 
201
- function detectTerminals() {
202
- const list = []
203
- if (isWin) {
204
- list.push('wt', 'cmd')
205
- return list
191
+ function resolveTimerMode(termPref) {
192
+ const pref = termPref ?? 'auto'
193
+ if (pref === 'none' || pref === 'headless') return 'none'
194
+ if ((pref === 'auto' || pref === 'tmux' || pref === 'tmux-popup') && process.env.TMUX) {
195
+ return 'tmux-popup'
206
196
  }
207
- // Prefer a modal overlay when Claude Code is running inside tmux.
208
- if (process.env.TMUX) list.push('tmux-popup')
209
- if (process.env.STY) list.push('screen')
210
- if (process.env.KITTY_WINDOW_ID) list.push('kitty')
211
- if (process.env.TERM_PROGRAM === 'WezTerm') list.push('wezterm')
212
- list.push('tmux-window', 'gnome-terminal', 'xfce4-terminal', 'konsole', 'xterm', 'alacritty', 'wezterm', 'kitty')
213
- return list
197
+ return 'none'
214
198
  }
215
199
 
216
200
  function buildCmd(term, tsx, entryFile, sessionId) {
217
- // Quote paths for Windows (handles spaces in paths like AppData\Roaming\npm\...)
218
- const q = isWin ? (p) => `"${p}"` : (p) => p
219
- const inner = isWin
220
- ? `${q(tsx)} ${q(entryFile)} ${sessionId}`
221
- : `${tsx} ${entryFile} ${sessionId}`
222
201
  switch (term) {
223
- case 'wt': return ['wt', 'new-tab', '--', 'cmd.exe', '/k', inner]
224
- case 'cmd': return ['cmd.exe', '/c', `start cmd.exe /k "${inner}"`]
225
- case 'tmux':
226
202
  case 'tmux-popup': return buildTmuxPopupCmd(tsx, entryFile, sessionId)
227
- case 'tmux-window': return ['tmux', 'new-window', inner]
228
- case 'screen': return ['screen', '-X', 'screen', 'bash', '-c', inner]
229
- case 'gnome-terminal': return ['gnome-terminal', '--', 'bash', '-c', inner]
230
- case 'xfce4-terminal': return ['xfce4-terminal', '-e', inner]
231
- case 'konsole': return ['konsole', '-e', inner]
232
- case 'xterm': return ['xterm', '-e', inner]
233
- case 'alacritty': return ['alacritty', '-e', 'bash', '-c', inner]
234
- case 'wezterm': return ['wezterm', 'start', '--', 'bash', '-c', inner]
235
- case 'kitty': return ['kitty', 'bash', '-c', inner]
236
203
  default: return null
237
204
  }
238
205
  }
@@ -279,8 +246,11 @@ function buildTmuxPopupCmd(tsx, entryFile, sessionId) {
279
246
  'tmux',
280
247
  'display-popup',
281
248
  '-E',
282
- '-w', '90%',
283
- '-h', '90%',
249
+ '-w', '100%',
250
+ '-h', '100%',
251
+ '-x', '0',
252
+ '-y', '0',
253
+ '-B',
284
254
  '-T', 'Pomodoro',
285
255
  `bash -lc ${shellQuote(timerCmd)}`,
286
256
  ]
package/install.mjs CHANGED
@@ -109,23 +109,7 @@ argument-hint: "[duration e.g. 25m] [task description]"
109
109
  node ${pomodoroPath} start $ARGUMENTS
110
110
  \`\`\`
111
111
 
112
- ## Step 2: Check if timer window launched
113
-
114
- Read the output from Step 1 carefully.
115
-
116
- If the output contains **\`POMODORO_TIMER_NOT_LAUNCHED\`**, the system could not open a separate timer window (common in SSH, VSCode, or headless environments). In this case you MUST tell the user BEFORE doing any work:
117
-
118
- > ⚠️ **No timer window could be opened automatically.**
119
- >
120
- > Run one of these in another terminal to control your Pomodoro:
121
- > - **Watch timer:** (the command shown on the "To watch" line above)
122
- > - **End session:** (the command shown on the "To end" line above)
123
- >
124
- > I'll now work on your task. The session will stay active until you run the stop command.
125
-
126
- After telling the user that once, continue immediately. Do not wait for a reply.
127
-
128
- ## Step 3: Work autonomously during the focus session
112
+ ## Step 2: Work autonomously during the focus session
129
113
 
130
114
  The user has started a Pomodoro focus session and **will not be checking the screen** until the timer ends. Do not interrupt them.
131
115
 
@@ -136,6 +120,7 @@ The user has started a Pomodoro focus session and **will not be checking the scr
136
120
  - Focus only on what is **unambiguously clear** from the task description
137
121
  - If you encounter something that requires a user decision, **stop and record it** in \`.claude/pomodoro-pending.md\` — do NOT make assumptions or proceed on the user's behalf
138
122
  - Do not send notifications or ask questions — the user is in focus mode
123
+ - If a timer UI is available, it may appear as a tmux popup. If not, continue headlessly — do not mention missing timer UI to the user unless they ask
139
124
  - When you have done all you can, write a summary to \`.claude/pomodoro-summary.md\`
140
125
  - Then wait quietly — the Pomodoro hook will manage the session lifecycle
141
126
  `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-pomo",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "You and your agent, both in flow. A Pomodoro timer for Claude Code that keeps agents working autonomously while you stay deep in focus — uninterrupted.",
5
5
  "type": "module",
6
6
  "bin": {