claude-ai-office 0.25.6 โ†’ 0.29.1

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.en.md CHANGED
@@ -61,7 +61,7 @@ node bin/ai-office.js # or: npm run install-hooks && npm start
61
61
 
62
62
  | Area | Contents |
63
63
  |---|---|
64
- | **Left: Floors** | One floor per git project (repository root). Worktrees share the floor and show their branch (โއ). Opening a floor lists its sessions with `waiting` and `viewing` badges. ๐ŸŽจ on the selected floor picks that floor's interior preset (Warm Wood ยท Cool Gray ยท Mint ยท Lavender ยท Sand ยท Pastel; assigned automatically by default). "Follow the latest session" (`A`) moves the selection to the most recently active session; when it is off, the last floor and session you looked at are restored next time |
64
+ | **Left: Floors** | One floor per git project (repository root). Worktrees share the floor and show their branch (โއ). Opening a floor lists its sessions with `waiting` and `viewing` badges. By default only the selected floor is open; **Expand all โ†” Collapse all** in the header opens or closes every floor's session list at once (clicking a floor while all are collapsed opens that floor; remembered in the browser). ๐ŸŽจ on the selected floor picks that floor's interior preset (Warm Wood ยท Cool Gray ยท Mint ยท Lavender ยท Sand ยท Pastel; assigned automatically by default). "Follow the latest session" (`A`) moves the selection to the most recently active session; when it is off, the last floor and session you looked at are restored next time |
65
65
  | **Center: Office** | Drag to pan, wheel or buttons to zoom, `โŸฒ` to reset, pinch on touch screens. Click a character to select its session; hover for a tooltip (current action, target file, prompt, branch, path). ๐Ÿ“ **Follow** (`F`) keeps the camera on the selected session's Claude. ๐Ÿข **Building view** (`O`) appears when there are two or more floors |
66
66
  | **Right panel** | Session card (project path ยท session id ยท character name ยท copy the resume command ยท ๐Ÿ—‘ dismiss ended sessions), people in the office (room ยท speech bubble ยท elapsed time), activity log (search with `/`, selected session only), legend (click the title to collapse) |
67
67
 
@@ -157,9 +157,9 @@ With two or more floors, ๐Ÿข **Building view** (`O`) appears in the header. Flo
157
157
 
158
158
  ## Menu bar app (Tauri)
159
159
 
160
- A resident app that shows the web UI in a window. It starts the Node server itself (or reuses one that is already running) and lives in the menu bar / system tray with Open, Hide, Always on top, Reinstall hooks, Check for updates and Quit. When sessions are waiting for you, the menu bar shows `๐Ÿ™‹ n`. Closing the window hides it; Quit stops the server too. Node is bundled: on first launch the app copies the server files to `~/.ai-office/app` and the Node binary to `~/.ai-office/node`, then registers the hooks, so moving or deleting the app does not break them.
160
+ A resident app that shows the web UI in a window. It starts the Node server itself (or reuses one that is already running) and lives in the menu bar / system tray; left- or right-click the icon for the menu: Open, Hide, Always on top, Launch at login, Reinstall hooks, Check for updates, Apply update and Quit. When a session is waiting for you or an update is ready, a **red dot** appears on the menu bar icon and on the Dock (Windows: taskbar) icon, like a chat app; there is no count, and the tooltip says what it is. **Launch at login** is turned on at first run; when started at login the app stays in the menu bar without a window. You can turn it off from the menu. Closing the window hides it; Quit stops the server too. Node is bundled: on first launch the app copies the server files to `~/.ai-office/app` and the Node binary to `~/.ai-office/node`, then registers the hooks, so moving or deleting the app does not break them.
161
161
 
162
- **Updates**: the app checks for a new version 10 seconds after launch and every 6 hours, downloads it in the background, then shows โฌ† in the menu bar and enables "Apply update (restart)". Releases are built by GitHub Actions for macOS (Apple Silicon) and Windows (x64) and signed for the updater.
162
+ **Updates**: the app checks for a new version 10 seconds after launch and every 6 hours and only **downloads** it in the background (signature verified; a failed check is retried after 5 minutes), then shows the red dot and enables "Apply vX update (restart)". Applying stops the server, installs and restarts; nothing is installed without asking and the running app is never replaced underneath you. "Check for updates" in the menu shows whether you are up to date or why a check failed. Releases are built by GitHub Actions for macOS (Apple Silicon) and Windows (x64) and signed for the updater.
163
163
 
164
164
  > **Download**: [macOS AI-Office-mac-arm64.dmg](https://github.com/cozyuj/AI-office/releases/latest/download/AI-Office-mac-arm64.dmg) ยท [Windows AI-Office-windows-x64-setup.exe](https://github.com/cozyuj/AI-office/releases/latest/download/AI-Office-windows-x64-setup.exe) (always the latest; older versions in [Releases](https://github.com/cozyuj/AI-office/releases)). The macOS app is not notarized: **right-click โ†’ Open** the first time; on macOS 15+ use System Settings โ†’ Privacy & Security โ†’ **Open Anyway**, and if it still says "damaged", run `xattr -dr com.apple.quarantine "/Applications/AI Office.app"` once. To build it yourself:
165
165
 
package/README.md CHANGED
@@ -63,7 +63,7 @@ node bin/ai-office.js # ๋˜๋Š” npm run install-hooks && npm start
63
63
 
64
64
  | ์˜์—ญ | ๋‚ด์šฉ |
65
65
  |---|---|
66
- | **์ขŒ์ธก ์ธต๋ณ„ ์•ˆ๋‚ด** | git ํ”„๋กœ์ ํŠธ(์ €์žฅ์†Œ ๋ฃจํŠธ) = ์ธต. worktree ๋Š” ๊ฐ™์€ ์ธต์œผ๋กœ ๋ฌถ์ด๊ณ  ๋ธŒ๋žœ์น˜(โއ)๊ฐ€ ํ•จ๊ป˜ ๋ณด์ธ๋‹ค. ์ธต์„ ์—ด๋ฉด ์„ธ์…˜ ๋ชฉ๋ก โ€” `๋‹ต ๊ธฐ๋‹ค๋ฆผ`, `์ง€๊ธˆ ๋ณด๋Š” ์ค‘` ํ‘œ์‹œ. ์„ ํƒํ•œ ์ธต์˜ ๐ŸŽจ ๋กœ ๊ทธ ์ธต ์ธํ…Œ๋ฆฌ์–ด ์Šคํƒ€์ผ(๋”ฐ๋œปํ•œ ์šฐ๋“œยท์ฟจ ๊ทธ๋ ˆ์ดยท๋ฏผํŠธยท๋ผ๋ฒค๋”ยท์ƒŒ๋“œยทํŒŒ์Šคํ…”, ๊ธฐ๋ณธ์€ ์ธต๋งˆ๋‹ค ์ž๋™ ๋ฐฐ์ •)์„ ๊ณ ๋ฅธ๋‹ค. "์ตœ๊ทผ ์„ธ์…˜ ์ž๋™์œผ๋กœ ๋”ฐ๋ผ๊ฐ€๊ธฐ"(`A`)๋ฅผ ์ผœ๋ฉด ์ตœ์‹  ํ™œ๋™ ์„ธ์…˜์œผ๋กœ ์„ ํƒ์ด ์˜ฎ๊ฒจ๊ฐ€๊ณ , ๋„๋ฉด ๋งˆ์ง€๋ง‰์— ๋ณด๋˜ ์ธตยท์„ธ์…˜์„ ๋‹ค์Œ์— ์—ด ๋•Œ ๊ธฐ์–ตํ•œ๋‹ค |
66
+ | **์ขŒ์ธก ์ธต๋ณ„ ์•ˆ๋‚ด** | git ํ”„๋กœ์ ํŠธ(์ €์žฅ์†Œ ๋ฃจํŠธ) = ์ธต. worktree ๋Š” ๊ฐ™์€ ์ธต์œผ๋กœ ๋ฌถ์ด๊ณ  ๋ธŒ๋žœ์น˜(โއ)๊ฐ€ ํ•จ๊ป˜ ๋ณด์ธ๋‹ค. ์ธต์„ ์—ด๋ฉด ์„ธ์…˜ ๋ชฉ๋ก โ€” `๋‹ต ๊ธฐ๋‹ค๋ฆผ`, `์ง€๊ธˆ ๋ณด๋Š” ์ค‘` ํ‘œ์‹œ. ๊ธฐ๋ณธ์€ ์„ ํƒํ•œ ์ธต๋งŒ ์—ด๋ฆฌ๊ณ , ๋จธ๋ฆฌ์˜ **๋ชจ๋‘ ํŽผ์น˜๊ธฐ โ†” ๋ชจ๋‘ ์ ‘๊ธฐ** ๋กœ ๋ชจ๋“  ์ธต์˜ ์„ธ์…˜ ๋ชฉ๋ก์„ ํ•œ๊บผ๋ฒˆ์— ์—ด๊ณ  ๋‹ซ๋Š”๋‹ค(๋ชจ๋‘ ์ ‘ํžŒ ์ƒํƒœ์—์„œ ์ธต์„ ๋ˆ„๋ฅด๋ฉด ๊ทธ ์ธต์ด ์—ด๋ฆผ, ๋ธŒ๋ผ์šฐ์ €์— ๊ธฐ์–ต). ์„ ํƒํ•œ ์ธต์˜ ๐ŸŽจ ๋กœ ๊ทธ ์ธต ์ธํ…Œ๋ฆฌ์–ด ์Šคํƒ€์ผ(๋”ฐ๋œปํ•œ ์šฐ๋“œยท์ฟจ ๊ทธ๋ ˆ์ดยท๋ฏผํŠธยท๋ผ๋ฒค๋”ยท์ƒŒ๋“œยทํŒŒ์Šคํ…”, ๊ธฐ๋ณธ์€ ์ธต๋งˆ๋‹ค ์ž๋™ ๋ฐฐ์ •)์„ ๊ณ ๋ฅธ๋‹ค. "์ตœ๊ทผ ์„ธ์…˜ ์ž๋™์œผ๋กœ ๋”ฐ๋ผ๊ฐ€๊ธฐ"(`A`)๋ฅผ ์ผœ๋ฉด ์ตœ์‹  ํ™œ๋™ ์„ธ์…˜์œผ๋กœ ์„ ํƒ์ด ์˜ฎ๊ฒจ๊ฐ€๊ณ , ๋„๋ฉด ๋งˆ์ง€๋ง‰์— ๋ณด๋˜ ์ธตยท์„ธ์…˜์„ ๋‹ค์Œ์— ์—ด ๋•Œ ๊ธฐ์–ตํ•œ๋‹ค |
67
67
  | **์ค‘์•™ ์‚ฌ๋ฌด์‹ค** | ๋“œ๋ž˜๊ทธ ์ด๋™, ํœ /๋ฒ„ํŠผ ์คŒ, `โŸฒ` ์ดˆ๊ธฐ ์œ„์น˜. ์บ๋ฆญํ„ฐ ํด๋ฆญ โ†’ ์„ธ์…˜ ์„ ํƒ, ์บ๋ฆญํ„ฐ์— ๋งˆ์šฐ์Šค๋ฅผ ์˜ฌ๋ฆฌ๋ฉด ํˆดํŒ(์ง€๊ธˆ ํ•˜๋Š” ์ผยท๋Œ€์ƒ ํŒŒ์ผยท์š”์ฒญยท๋ธŒ๋žœ์น˜ยท๊ฒฝ๋กœ). ๐Ÿ“ **๋”ฐ๋ผ๊ฐ€๊ธฐ**(`F`) = ์นด๋ฉ”๋ผ๊ฐ€ ์„ ํƒ ์„ธ์…˜์˜ Claude ๋ฅผ ์ซ“์•„๊ฐ. ๐Ÿข **์ „์ฒด ๋ณด๊ธฐ**(`O`)๋Š” ์ธต์ด ๋‘˜ ์ด์ƒ์ผ ๋•Œ ๋‚˜ํƒ€๋‚œ๋‹ค |
68
68
  | **์šฐ์ธก ํŒจ๋„** | ์„ธ์…˜ ์นด๋“œ(ํ”„๋กœ์ ํŠธ ๊ฒฝ๋กœ ยท ์„ธ์…˜ id ยท ์บ๋ฆญํ„ฐ ์ด๋ฆ„ ยท ์ด์–ด๊ฐ€๊ธฐ ๋ช…๋ น ๋ณต์‚ฌ ยท ๋๋‚œ ์„ธ์…˜ ๐Ÿ—‘ ์น˜์šฐ๊ธฐ), ์‚ฌ๋ฌด์‹ค ์‚ฌ๋žŒ๋“ค(๋ฐฉยท๋งํ’์„ ยท๊ฒฝ๊ณผ), ํ™œ๋™ ๋กœ๊ทธ(๊ฒ€์ƒ‰ `/`, ์„ ํƒ ์„ธ์…˜๋งŒ), ๋ฒ”๋ก€(์ œ๋ชฉ ํด๋ฆญ์œผ๋กœ ์ ‘๊ธฐ) |
69
69
 
@@ -159,9 +159,9 @@ node bin/ai-office.js # ๋˜๋Š” npm run install-hooks && npm start
159
159
 
160
160
  ## ๋ฉ”๋‰ด๋ฐ” ์•ฑ (Tauri)
161
161
 
162
- ์›น ๋ฒ„์ „์„ ๊ทธ๋Œ€๋กœ ์ฐฝ์— ๋‹ด์€ ์ƒ์ฃผ ์•ฑ์ž…๋‹ˆ๋‹ค(๋งฅ ๋ฉ”๋‰ด๋ฐ” ยท Windows ํŠธ๋ ˆ์ด). ์•ฑ์ด Node ์„œ๋ฒ„๋ฅผ ์ง์ ‘ ๋„์šฐ๊ณ (์ด๋ฏธ ๋–  ์žˆ์œผ๋ฉด ์žฌ์‚ฌ์šฉ) ์•„์ด์ฝ˜ ๋ฉ”๋‰ด์—์„œ ์—ด๊ธฐ/์ˆจ๊ธฐ๊ธฐ/ํ•ญ์ƒ ์œ„/ํ›… ๋‹ค์‹œ ์„ค์น˜/์—…๋ฐ์ดํŠธ ํ™•์ธ/์ข…๋ฃŒ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ต์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์„ธ์…˜์ด ์žˆ์œผ๋ฉด ๋ฉ”๋‰ด๋ฐ”์— `๐Ÿ™‹ n` ์ด ๋œน๋‹ˆ๋‹ค. ์ฐฝ์„ ๋‹ซ์•„๋„ ๋ฉ”๋‰ด๋ฐ”์— ๋‚จ๊ณ , ์ข…๋ฃŒํ•˜๋ฉด ์„œ๋ฒ„๋„ ํ•จ๊ป˜ ๋‚ด๋ ค๊ฐ‘๋‹ˆ๋‹ค(์•ฑ์ด ๊ฐ•์ œ ์ข…๋ฃŒ๋ผ๋„ ์„œ๋ฒ„๊ฐ€ ์Šค์Šค๋กœ ๋๋‚ฉ๋‹ˆ๋‹ค). ์•ฑ์—๋Š” Node ๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ๊ณ , ์ฒซ ์‹คํ–‰ ๋•Œ ์„œ๋ฒ„ ํŒŒ์ผ์„ `~/.ai-office/app` ์—, Node ๋ฅผ `~/.ai-office/node` ์— ๋ณต์‚ฌํ•˜๊ณ  ๊ทธ ๊ฒฝ๋กœ๋กœ ํ›…์„ ๋“ฑ๋กํ•˜๋ฏ€๋กœ ์•ฑ์„ ์˜ฎ๊ธฐ๊ฑฐ๋‚˜ ์ง€์›Œ๋„ ํ›…์ด ๊นจ์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
162
+ ์›น ๋ฒ„์ „์„ ๊ทธ๋Œ€๋กœ ์ฐฝ์— ๋‹ด์€ ์ƒ์ฃผ ์•ฑ์ž…๋‹ˆ๋‹ค(๋งฅ ๋ฉ”๋‰ด๋ฐ” ยท Windows ํŠธ๋ ˆ์ด). ์•ฑ์ด Node ์„œ๋ฒ„๋ฅผ ์ง์ ‘ ๋„์šฐ๊ณ (์ด๋ฏธ ๋–  ์žˆ์œผ๋ฉด ์žฌ์‚ฌ์šฉ) ์•„์ด์ฝ˜์„ ์™ผ์ชฝ์ด๋‚˜ ์˜ค๋ฅธ์ชฝ ํด๋ฆญํ•˜๋ฉด ๋ฉ”๋‰ด๊ฐ€ ๋œน๋‹ˆ๋‹ค. ๋ฉ”๋‰ด๋Š” ์—ด๊ธฐ ยท ์ˆจ๊ธฐ๊ธฐ ยท ํ•ญ์ƒ ์œ„ ยท ๋กœ๊ทธ์ธ ์‹œ ์ž๋™ ์‹คํ–‰ ยท ํ›… ๋‹ค์‹œ ์„ค์น˜ ยท ์—…๋ฐ์ดํŠธ ํ™•์ธ ยท ์—…๋ฐ์ดํŠธ ์ ์šฉ ยท ์ข…๋ฃŒ์ž…๋‹ˆ๋‹ค. ๋‹ต์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์„ธ์…˜์ด ์žˆ๊ฑฐ๋‚˜ ๋ฐ›์•„ ๋‘” ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์นด์นด์˜คํ†ก์ฒ˜๋Ÿผ ๋ฉ”๋‰ด๋ฐ” ์•„์ด์ฝ˜๊ณผ Dock(Windows ๋Š” ์ž‘์—… ํ‘œ์‹œ์ค„) ์•„์ด์ฝ˜์— **๋นจ๊ฐ„ ์ **์ด ๋œน๋‹ˆ๋‹ค. ์ˆซ์ž๋Š” ์—†๊ณ , ๋ฌด์—‡์ธ์ง€๋Š” ์•„์ด์ฝ˜์— ๋งˆ์šฐ์Šค๋ฅผ ์˜ฌ๋ฆฌ๋ฉด ํˆดํŒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. **๋กœ๊ทธ์ธ ์‹œ ์ž๋™ ์‹คํ–‰**์€ ์ฒ˜์Œ ์‹คํ–‰ ๋•Œ ์ผœ์ง€๋ฉฐ, ์ž๋™์œผ๋กœ ์ผœ์งˆ ๋• ์ฐฝ ์—†์ด ๋ฉ”๋‰ด๋ฐ”์—๋งŒ ๋œน๋‹ˆ๋‹ค. ๋ฉ”๋‰ด์—์„œ ๋Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฐฝ์„ ๋‹ซ์•„๋„ ๋ฉ”๋‰ด๋ฐ”์— ๋‚จ๊ณ , ์ข…๋ฃŒํ•˜๋ฉด ์„œ๋ฒ„๋„ ํ•จ๊ป˜ ๋‚ด๋ ค๊ฐ‘๋‹ˆ๋‹ค(์•ฑ์ด ๊ฐ•์ œ ์ข…๋ฃŒ๋ผ๋„ ์„œ๋ฒ„๊ฐ€ ์Šค์Šค๋กœ ๋๋‚ฉ๋‹ˆ๋‹ค). ์•ฑ์—๋Š” Node ๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ๊ณ , ์ฒซ ์‹คํ–‰ ๋•Œ ์„œ๋ฒ„ ํŒŒ์ผ์„ `~/.ai-office/app` ์—, Node ๋ฅผ `~/.ai-office/node` ์— ๋ณต์‚ฌํ•˜๊ณ  ๊ทธ ๊ฒฝ๋กœ๋กœ ํ›…์„ ๋“ฑ๋กํ•˜๋ฏ€๋กœ ์•ฑ์„ ์˜ฎ๊ธฐ๊ฑฐ๋‚˜ ์ง€์›Œ๋„ ํ›…์ด ๊นจ์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
163
163
 
164
- **์ž๋™ ์—…๋ฐ์ดํŠธ**: ์•ฑ์ด ์‹œ์ž‘ 10์ดˆ ๋’ค์™€ 6์‹œ๊ฐ„๋งˆ๋‹ค ์ƒˆ ๋ฒ„์ „์„ ํ™•์ธํ•ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ๋ฐ›์•„ ๋‘๊ณ , ๋ฉ”๋‰ด๋ฐ”์— โฌ† ๋ฅผ ๋„์šฐ๋ฉฐ ๋ฉ”๋‰ด์˜ "์—…๋ฐ์ดํŠธ ์ ์šฉ (๋‹ค์‹œ ์‹œ์ž‘)" ์ด ์ผœ์ง‘๋‹ˆ๋‹ค. ๋ฆด๋ฆฌ์Šค๋Š” ํƒœ๊ทธ๋ฅผ ์˜ฌ๋ฆฌ๋ฉด GitHub Actions ๊ฐ€ ๋งฅ(Apple Silicon)ยทWindows(x64) ๋กœ ๋นŒ๋“œํ•˜๊ณ  ์„œ๋ช…ํ•ด ์˜ฌ๋ฆฝ๋‹ˆ๋‹ค.
164
+ **์ž๋™ ์—…๋ฐ์ดํŠธ**: ์•ฑ์ด ์‹œ์ž‘ 10์ดˆ ๋’ค์™€ 6์‹œ๊ฐ„๋งˆ๋‹ค ์ƒˆ ๋ฒ„์ „์„ ํ™•์ธํ•ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ **๋ฐ›์•„ ๋‘๊ธฐ๋งŒ** ํ•˜๊ณ (์„œ๋ช… ๊ฒ€์ฆ๊นŒ์ง€, ํ™•์ธ์— ์‹คํŒจํ•˜๋ฉด 5๋ถ„ ๋’ค ๋‹ค์‹œ), ๋นจ๊ฐ„ ์ ์„ ๋„์šฐ๋ฉฐ ๋ฉ”๋‰ด์˜ "vX ์—…๋ฐ์ดํŠธ ์ ์šฉ (๋‹ค์‹œ ์‹œ์ž‘)" ์ด ์ผœ์ง‘๋‹ˆ๋‹ค. ๋ˆ„๋ฅด๋ฉด ์„œ๋ฒ„๋ฅผ ๋‚ด๋ฆฌ๊ณ  ์„ค์น˜ํ•œ ๋’ค ๋‹ค์‹œ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๋ฌป์ง€ ์•Š๊ณ  ์„ค์น˜ํ•˜๊ฑฐ๋‚˜ ์“ฐ๋˜ ์ค‘์— ์•ฑ ํŒŒ์ผ์„ ๋ฐ”๊พธ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฉ”๋‰ด์˜ "์—…๋ฐ์ดํŠธ ํ™•์ธ" ์— ์ตœ์‹  ์—ฌ๋ถ€๋‚˜ ์‹คํŒจ ์ด์œ ๊ฐ€ ๋ณด์ž…๋‹ˆ๋‹ค. ๋ฆด๋ฆฌ์Šค๋Š” ํƒœ๊ทธ๋ฅผ ์˜ฌ๋ฆฌ๋ฉด GitHub Actions ๊ฐ€ ๋งฅ(Apple Silicon)ยทWindows(x64) ๋กœ ๋นŒ๋“œํ•˜๊ณ  ์„œ๋ช…ํ•ด ์˜ฌ๋ฆฝ๋‹ˆ๋‹ค.
165
165
 
166
166
  > **๋‹ค์šด๋กœ๋“œ**: โฌ‡๏ธ **[๋งฅ AI-Office-mac-arm64.dmg](https://github.com/cozyuj/AI-office/releases/latest/download/AI-Office-mac-arm64.dmg)** ยท **[Windows AI-Office-windows-x64-setup.exe](https://github.com/cozyuj/AI-office/releases/latest/download/AI-Office-windows-x64-setup.exe)** (ํ•ญ์ƒ ์ตœ์‹ ) ยท ์ด์ „ ๋ฒ„์ „์€ [Releases](https://github.com/cozyuj/AI-office/releases). DMG ๋ฅผ ์—ด์–ด `AI Office.app` ์„ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ํด๋”์— ๋„ฃ์œผ์„ธ์š”. ์ฝ”๋“œ ์„œ๋ช…์ด ์—†์–ด ์ฒ˜์Œ์—” "ํ™•์ธ๋˜์ง€ ์•Š์€ ๊ฐœ๋ฐœ์ž" ๊ฒฝ๊ณ ๊ฐ€ ๋œจ๋‹ˆ ์•ฑ์„ **์šฐํด๋ฆญ โ†’ ์—ด๊ธฐ** ๋กœ ํ•œ ๋ฒˆ ํ—ˆ์šฉํ•˜๊ณ , macOS 15 ์ด์ƒ์—์„œ ์•ˆ ์—ด๋ฆฌ๋ฉด ์‹œ์Šคํ…œ ์„ค์ • โ†’ ๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ ๋ฐ ๋ณด์•ˆ โ†’ **๊ทธ๋ž˜๋„ ์—ด๊ธฐ**, ๊ทธ๋ž˜๋„ "์†์ƒ๋จ" ์ด๋ผ๊ณ  ๋‚˜์˜ค๋ฉด ํ„ฐ๋ฏธ๋„์—์„œ `xattr -dr com.apple.quarantine "/Applications/AI Office.app"` ๋ฅผ ํ•œ ๋ฒˆ ์‹คํ–‰ํ•˜์„ธ์š”. Intel ๋งฅยทLinux ๋Š” ์œ„์˜ `npx claude-ai-office` ํ•œ ์ค„๋กœ ์›น ๋ฒ„์ „์„ ์“ฐ์„ธ์š”. ์ง์ ‘ ๋นŒ๋“œํ•˜๋ ค๋ฉด:
167
167
 
package/lib/state.js CHANGED
@@ -240,6 +240,7 @@ function createState({ me = 'me', statFile = defaultStat, titleOf = defaultTitle
240
240
  function apply(payload, now = Date.now()) {
241
241
  if (!payload || typeof payload !== 'object') return;
242
242
  const ev = normalize(payload);
243
+ if (ev.event === 'SessionEnd' && !sessions.has(ev.sessionId)) return; // ๋ชจ๋ฅด๋Š” ์„ธ์…˜์˜ ์ข…๋ฃŒ(์น˜์šด ์„ธ์…˜ ์žฌ์ƒ ๋“ฑ)๋กœ ๋นˆ ์ธต์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค
243
244
  const { session: s, floor } = sessionFor(ev, now);
244
245
  let entry = null;
245
246
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-ai-office",
3
- "version": "0.25.6",
3
+ "version": "0.29.1",
4
4
  "description": "Claude Code ์„ธ์…˜ ํ™œ๋™์„ ์•„์ด์†Œ๋ฉ”ํŠธ๋ฆญ ์‚ฌ๋ฌด์‹ค๋กœ ์‹ค์‹œ๊ฐ„ ์‹œ๊ฐํ™”",
5
5
  "keywords": [
6
6
  "claude",
package/public/index.html CHANGED
@@ -14,6 +14,7 @@
14
14
  <div class="panel-head">
15
15
  <span class="panel-title">์ธต๋ณ„ ์•ˆ๋‚ด</span>
16
16
  <span class="panel-sub">FLOOR GUIDE</span>
17
+ <button id="floors-fold" class="tool fold-btn" title="๋ชจ๋“  ์ธต์˜ ์„ธ์…˜ ๋ชฉ๋ก ์—ด๊ธฐ">๋ชจ๋‘ ํŽผ์น˜๊ธฐ</button>
17
18
  </div>
18
19
  <div id="floors" class="scroll"></div>
19
20
  <div class="panel-foot" id="left-foot"></div>
package/public/js/i18n.js CHANGED
@@ -73,6 +73,7 @@ const DICT = {
73
73
  '์ง€๊ธˆ ๋ณด๋Š” ์ธต์˜ ์ธํ…Œ๋ฆฌ์–ด ํ”„๋ฆฌ์…‹ (์ธต๋ณ„ ์•ˆ๋‚ด์˜ ๐ŸŽจ ์™€ ๊ฐ™์Œ) โ€” ์ƒ‰๊ณผ ์‚ฌ๋ฌด์‹ค ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€๋‹ˆ๋‹ค': 'Interior preset of the floor you are viewing (same as ๐ŸŽจ in Floors) โ€” changes colors and the office layout',
74
74
  '์ธต์„ ๊ฑด๋ฌผ์ฒ˜๋Ÿผ ์Œ“์•„ ํ•œ๋ˆˆ์— (O)': 'Stack the floors like a building (O)', 'ํ‚ค๋ณด๋“œ ๋‹จ์ถ•ํ‚ค ํ‘œ': 'Keyboard shortcut table', 'ํ„ฐ๋ฏธ๋„์—์„œ ์ด ์„ธ์…˜์„ ์ด์–ด๊ฐ€๋Š” ๋ช…๋ น์„ ๋ณต์‚ฌ': 'Copy the command that resumes this session in a terminal', '์ด ์ธต ์ธํ…Œ๋ฆฌ์–ด ์Šคํƒ€์ผ ๊ณ ๋ฅด๊ธฐ': 'Pick this floor\'s interior style',
75
75
  '์ด ๋ธŒ๋ผ์šฐ์ €๋Š” ์•Œ๋ฆผ์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค': 'This browser does not support notifications', '๋‹ต์„ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์–ด์š”': 'waiting for your answer',
76
+ '๋ชจ๋‘ ํŽผ์น˜๊ธฐ': 'Expand all', '๋ชจ๋‘ ์ ‘๊ธฐ': 'Collapse all', '๋ชจ๋“  ์ธต์˜ ์„ธ์…˜ ๋ชฉ๋ก ์—ด๊ธฐ': 'Open the session list of every floor', '๋ชจ๋“  ์ธต์˜ ์„ธ์…˜ ๋ชฉ๋ก ๋‹ซ๊ธฐ': 'Close the session list of every floor', '์„ธ์…˜ ์—†์Œ': 'No sessions',
76
77
  'ํ•œ๊ตญ์–ด / English': 'ํ•œ๊ตญ์–ด / English', 'ํ™”๋ฉด ์–ธ์–ด': 'UI language',
77
78
  '๋“œ๋ž˜๊ทธ๋กœ ์ด๋™': 'Drag to pan', 'ํœ ๋กœ ํ™•๋Œ€': 'wheel to zoom', '์บ๋ฆญํ„ฐ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์„ธ์…˜ ์„ ํƒ': 'click a character to select its session',
78
79
  '์ˆซ์ž ์ธต ๋ฒˆํ˜ธ๋กœ ์ด๋™ (12F ๋Š” 1,2 ์—ฐํƒ€)': 'Digits go to a floor number (12F: press 1, 2)', 'โ†/โ†’ ์ด์ „ยท๋‹ค์Œ ์ธต': 'โ†/โ†’ previous ยท next floor', 'F ๋”ฐ๋ผ๊ฐ€๊ธฐ': 'F follow', 'A ์ž๋™ ๋”ฐ๋ผ๊ฐ€๊ธฐ': 'A auto-follow', 'D ๋ฐ๋ชจ': 'D demo', 'O ์ „์ฒด ๋ณด๊ธฐ': 'O building view', 'B ๋งํ’์„ ': 'B bubbles', 'S ์†Œ๋ฆฌ': 'S sound', 'T ํ…Œ๋งˆ': 'T theme', '/ ๋กœ๊ทธ ๊ฒ€์ƒ‰': '/ log search', 'Esc ๋‹ซ๊ธฐ': 'Esc close', '? ์ด ๋„์›€๋ง': '? this help',
@@ -87,7 +87,8 @@ export function renderFloors() {
87
87
  ${selected ? '<button class="floor-style" title="์ด ์ธต ์ธํ…Œ๋ฆฌ์–ด ์Šคํƒ€์ผ ๊ณ ๋ฅด๊ธฐ">๐ŸŽจ</button>' : ''}
88
88
  <span class="dot ${status}"></span>
89
89
  </div>`;
90
- if (!selected) return `<div class="floor">${head}</div>`;
90
+ const open = store.isFloorOpen(f.id);
91
+ if (!open) return `<div class="floor ${selected ? 'selected' : ''}">${head}</div>`;
91
92
  const list = sessions.map((s) => `
92
93
  <div class="session ${s.id === store.selectedSessionId ? 'selected' : ''} ${s.title ? '' : 'untitled'} ${s.status === 'away' || s.status === 'ended' ? 'away' : ''}" data-session="${esc(s.id)}" data-tip="${esc(s.title || s.id)}">
93
94
  <span class="dot ${s.status}"></span>
@@ -103,12 +104,14 @@ export function renderFloors() {
103
104
  </span>` : ''}
104
105
  </span>
105
106
  </div>`).join('');
106
- return `<div class="floor selected">${head}
107
+ return `<div class="floor open ${selected ? 'selected' : ''}">${head}
107
108
  <div class="floor-sessions">
108
- <label class="follow"><input type="checkbox" id="auto-follow" ${store.autoFollow ? 'checked' : ''}> ์ตœ๊ทผ ์„ธ์…˜ ์ž๋™์œผ๋กœ ๋”ฐ๋ผ๊ฐ€๊ธฐ</label>
109
- ${list}
109
+ ${selected ? `<label class="follow"><input type="checkbox" id="auto-follow" ${store.autoFollow ? 'checked' : ''}> ์ตœ๊ทผ ์„ธ์…˜ ์ž๋™์œผ๋กœ ๋”ฐ๋ผ๊ฐ€๊ธฐ</label>` : ''}
110
+ ${list || '<div class="muted" style="padding:4px 8px">์„ธ์…˜ ์—†์Œ</div>'}
110
111
  </div></div>`;
111
112
  }).join('');
113
+ const fold = $('floors-fold');
114
+ if (fold) { const all = store.allFloorsOpen(); fold.textContent = all ? '๋ชจ๋‘ ์ ‘๊ธฐ' : '๋ชจ๋‘ ํŽผ์น˜๊ธฐ'; fold.title = all ? '๋ชจ๋“  ์ธต์˜ ์„ธ์…˜ ๋ชฉ๋ก ๋‹ซ๊ธฐ' : '๋ชจ๋“  ์ธต์˜ ์„ธ์…˜ ๋ชฉ๋ก ์—ด๊ธฐ'; fold.disabled = floors.length < 1; }
112
115
  $('left-foot').textContent = `ํ”„๋กœ์ ํŠธ ${floors.length}๊ฐœ ยท ์„ธ์…˜ ${store.sessions.size}๊ฐœ${store.version ? ` ยท v${store.version}` : ''}`;
113
116
  }
114
117
 
@@ -181,6 +184,7 @@ export function bindPanelEvents() {
181
184
  const floor = e.target.closest('[data-floor]');
182
185
  if (floor) store.selectFloor(floor.dataset.floor);
183
186
  });
187
+ $('floors-fold').addEventListener('click', () => store.toggleAllFloors());
184
188
  $('log-search').addEventListener('input', (e) => store.setLogFilter({ q: e.target.value }));
185
189
  $('log-mine').addEventListener('click', () => store.setLogFilter({ mine: !store.logFilter.mine }));
186
190
  // ์„ธ์…˜ ์บ๋ฆญํ„ฐ ์ด๋ฆ„: ์ž…๋ ฅ(๋นˆ ๊ฐ’์ด๋ฉด ์ž๋™ ๋ณ„๋ช…์œผ๋กœ) ยท ๐ŸŽฒ ๋‹ค๋ฅธ ๋ณ„๋ช…
@@ -39,6 +39,7 @@ class Store {
39
39
  this.booted = false; // ์ฒซ ์Šค๋ƒ…์ƒท์—์„œ๋งŒ ๋งˆ์ง€๋ง‰ ์„ ํƒ์„ ๋ณต์›
40
40
  this.followCamera = false; // ์„ ํƒ ์„ธ์…˜ ์บ๋ฆญํ„ฐ๋ฅผ ์นด๋ฉ”๋ผ๊ฐ€ ๋”ฐ๋ผ๊ฐ
41
41
  this.bubbleMode = 'all'; // 'all' | 'selected'
42
+ this.floorFold = (() => { const v = ls.get('aiOffice.floorFold'); return v === 'all' || v === 'none' ? v : 'auto'; })(); // ์ธต๋ณ„ ์•ˆ๋‚ด: auto(์„ ํƒํ•œ ์ธต๋งŒ) ยท all ยท none
42
43
  this.sound = (() => { try { return localStorage.getItem('aiOffice.sound') === 'on'; } catch { return false; } })(); // ๋Œ€๊ธฐ ์•Œ๋ฆผ ์†Œ๋ฆฌ
43
44
  this.soundScope = ls.get('aiOffice.soundScope') === 'all' ? 'all' : 'waiting'; // 'waiting' ๋‹ต ๊ธฐ๋‹ค๋ฆผ๋งŒ | 'all' ์‹คํŒจยท์ข…๋ฃŒ๋„
44
45
  this.ambient = (() => { try { return localStorage.getItem('aiOffice.ambient') !== 'off'; } catch { return true; } })(); // ์‰ฌ๋Š” ์บ๋ฆญํ„ฐ ์ž์œจ ํ–‰๋™
@@ -142,7 +143,15 @@ class Store {
142
143
  }
143
144
  }
144
145
 
146
+ /** ์ธต ๋ชฉ๋ก์—์„œ ์ด ์ธต์˜ ์„ธ์…˜ ๋ชฉ๋ก์„ ํŽผ์น ์ง€ (FE-47) */
147
+ isFloorOpen(floorId) { return this.floorFold === 'all' || (this.floorFold === 'auto' && floorId === this.selectedFloorId); }
148
+ allFloorsOpen() { const fs = [...this.floors.keys()]; return fs.length > 0 && fs.every((id) => this.isFloorOpen(id)); }
149
+ setFloorFold(v) { this.floorFold = v === 'all' || v === 'none' ? v : 'auto'; ls.set('aiOffice.floorFold', this.floorFold === 'auto' ? null : this.floorFold); this.emit('option'); }
150
+ /** ๋ชจ๋‘ ํŽผ์น˜๊ธฐ โ†” ๋ชจ๋‘ ์ ‘๊ธฐ */
151
+ toggleAllFloors() { this.setFloorFold(this.allFloorsOpen() ? 'none' : 'all'); }
152
+
145
153
  selectFloor(id) {
154
+ if (this.floorFold === 'none') this.setFloorFold('auto'); // ๋ชจ๋‘ ์ ‘ํžŒ ์ƒํƒœ์—์„œ ์ธต์„ ๊ณ ๋ฅด๋ฉด ์ง€๊ธˆ์ฒ˜๋Ÿผ ๊ทธ ์ธต์ด ์—ด๋ฆฐ๋‹ค
146
155
  this.setAutoFollowFlag(false);
147
156
  this.selectedFloorId = id;
148
157
  this.selectedSessionId = null;
package/public/style.css CHANGED
@@ -38,12 +38,15 @@ code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background:
38
38
  #floors { padding: 8px; display: flex; flex-direction: column; gap: 6px; flex: 1; }
39
39
  .floor { border: 1px solid var(--line); border-radius: 10px; background: #fafbfc; overflow: hidden; }
40
40
  .floor.selected { border-color: var(--accent); background: var(--accent-soft); }
41
+ .panel-head .fold-btn { margin-left: auto; align-self: center; padding: 2px 9px; font-size: 11px; }
42
+ .floor.open:not(.selected) .floor-sessions { background: var(--panel); }
41
43
  .floor-row { display: flex; align-items: center; gap: 10px; padding: 9px 10px; cursor: pointer; }
42
44
  .floor-row:hover { background: rgba(0, 0, 0, .03); }
43
45
  .floor-badge { display: inline-flex; align-items: center; justify-content: center; min-width: 30px; height: 22px; padding: 0 6px; border-radius: 6px; background: #e8ebef; color: #4a515a; font-weight: 700; font-size: 11px; }
44
46
  .floor.selected .floor-badge, #office-head .floor-badge { background: var(--accent); color: #fff; }
45
- .floor-name { font-weight: 600; font-size: 13px; }
46
- .floor-meta { font-size: 11px; color: var(--muted); }
47
+ .floor-name { font-weight: 600; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
48
+ .floor-meta { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* ๋ฐฐ์ง€ยท๐ŸŽจ ์— ๋ฐ€๋ ค ๋‘ ์ค„๋กœ ๊บพ์ด์ง€ ์•Š๊ฒŒ (FE-49) */
49
+ .floor-row > .badge-wait, .floor-row > .floor-style, .floor-row > .dot { flex: none; }
47
50
  .floor-text { flex: 1; min-width: 0; }
48
51
  .floor-style { border: 1px solid var(--line); background: var(--panel); cursor: pointer; font-size: 13px; line-height: 1; padding: 3px 5px; border-radius: 6px; opacity: .95; }
49
52
  .floor-style:hover { opacity: 1; background: rgba(0, 0, 0, .06); }
package/server.js CHANGED
@@ -162,7 +162,12 @@ const server = http.createServer((req, res) => {
162
162
  if (del && req.method === 'DELETE') {
163
163
  const id = decodeURIComponent(del[1]);
164
164
  const found = !!state.get(id);
165
- if (found) state.remove(id);
165
+ if (found) {
166
+ state.remove(id);
167
+ // ์ €๋„์—๋„ ๋‚จ๊ฒจ ์„œ๋ฒ„๋ฅผ ๋‹ค์‹œ ์ผœ๋„ ์žฌ์ƒ์œผ๋กœ ๋˜์‚ด์•„๋‚˜์ง€ ์•Š๊ฒŒ (FE-49). ์žฌ์ƒํ•˜๋ฉด SessionEnd โ†’ 10์ดˆ ๋’ค ์ œ๊ฑฐ
168
+ const s0 = { session_id: id, hook_event_name: 'SessionEnd', reason: 'dismissed' };
169
+ if (!String(id).startsWith('demo')) journal.append(Date.now(), s0);
170
+ }
166
171
  res.writeHead(found ? 200 : 404, { 'Content-Type': MIME['.json'], 'Access-Control-Allow-Origin': '*' });
167
172
  return res.end(JSON.stringify({ removed: found, sessionId: id }));
168
173
  }