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 +3 -3
- package/README.md +3 -3
- package/lib/state.js +1 -0
- package/package.json +1 -1
- package/public/index.html +1 -0
- package/public/js/i18n.js +1 -0
- package/public/js/panels.js +8 -4
- package/public/js/store.js +9 -0
- package/public/style.css +5 -2
- package/server.js +6 -1
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
|
|
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
|
|
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 ์๋ฒ๋ฅผ ์ง์ ๋์ฐ๊ณ (์ด๋ฏธ ๋ ์์ผ๋ฉด ์ฌ์ฌ์ฉ)
|
|
162
|
+
์น ๋ฒ์ ์ ๊ทธ๋๋ก ์ฐฝ์ ๋ด์ ์์ฃผ ์ฑ์
๋๋ค(๋งฅ ๋ฉ๋ด๋ฐ ยท Windows ํธ๋ ์ด). ์ฑ์ด Node ์๋ฒ๋ฅผ ์ง์ ๋์ฐ๊ณ (์ด๋ฏธ ๋ ์์ผ๋ฉด ์ฌ์ฌ์ฉ) ์์ด์ฝ์ ์ผ์ชฝ์ด๋ ์ค๋ฅธ์ชฝ ํด๋ฆญํ๋ฉด ๋ฉ๋ด๊ฐ ๋น๋๋ค. ๋ฉ๋ด๋ ์ด๊ธฐ ยท ์จ๊ธฐ๊ธฐ ยท ํญ์ ์ ยท ๋ก๊ทธ์ธ ์ ์๋ ์คํ ยท ํ
๋ค์ ์ค์น ยท ์
๋ฐ์ดํธ ํ์ธ ยท ์
๋ฐ์ดํธ ์ ์ฉ ยท ์ข
๋ฃ์
๋๋ค. ๋ต์ ๊ธฐ๋ค๋ฆฌ๋ ์ธ์
์ด ์๊ฑฐ๋ ๋ฐ์ ๋ ์
๋ฐ์ดํธ๊ฐ ์์ผ๋ฉด ์นด์นด์คํก์ฒ๋ผ ๋ฉ๋ด๋ฐ ์์ด์ฝ๊ณผ Dock(Windows ๋ ์์
ํ์์ค) ์์ด์ฝ์ **๋นจ๊ฐ ์ **์ด ๋น๋๋ค. ์ซ์๋ ์๊ณ , ๋ฌด์์ธ์ง๋ ์์ด์ฝ์ ๋ง์ฐ์ค๋ฅผ ์ฌ๋ฆฌ๋ฉด ํดํ์ผ๋ก ๋ณด์
๋๋ค. **๋ก๊ทธ์ธ ์ ์๋ ์คํ**์ ์ฒ์ ์คํ ๋ ์ผ์ง๋ฉฐ, ์๋์ผ๋ก ์ผ์ง ๋ ์ฐฝ ์์ด ๋ฉ๋ด๋ฐ์๋ง ๋น๋๋ค. ๋ฉ๋ด์์ ๋ ์ ์์ต๋๋ค. ์ฐฝ์ ๋ซ์๋ ๋ฉ๋ด๋ฐ์ ๋จ๊ณ , ์ข
๋ฃํ๋ฉด ์๋ฒ๋ ํจ๊ป ๋ด๋ ค๊ฐ๋๋ค(์ฑ์ด ๊ฐ์ ์ข
๋ฃ๋ผ๋ ์๋ฒ๊ฐ ์ค์ค๋ก ๋๋ฉ๋๋ค). ์ฑ์๋ Node ๊ฐ ๋ด์ฅ๋์ด ์๊ณ , ์ฒซ ์คํ ๋ ์๋ฒ ํ์ผ์ `~/.ai-office/app` ์, Node ๋ฅผ `~/.ai-office/node` ์ ๋ณต์ฌํ๊ณ ๊ทธ ๊ฒฝ๋ก๋ก ํ
์ ๋ฑ๋กํ๋ฏ๋ก ์ฑ์ ์ฎ๊ธฐ๊ฑฐ๋ ์ง์๋ ํ
์ด ๊นจ์ง์ง ์์ต๋๋ค.
|
|
163
163
|
|
|
164
|
-
**์๋ ์
๋ฐ์ดํธ**: ์ฑ์ด ์์ 10์ด ๋ค์ 6์๊ฐ๋ง๋ค ์ ๋ฒ์ ์ ํ์ธํด ๋ฐฑ๊ทธ๋ผ์ด๋๋ก
|
|
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
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',
|
package/public/js/panels.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
// ์ธ์
์บ๋ฆญํฐ ์ด๋ฆ: ์
๋ ฅ(๋น ๊ฐ์ด๋ฉด ์๋ ๋ณ๋ช
์ผ๋ก) ยท ๐ฒ ๋ค๋ฅธ ๋ณ๋ช
|
package/public/js/store.js
CHANGED
|
@@ -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)
|
|
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
|
}
|