Skip to content

Commit 3a8fe27

Browse files
Merge pull request #7 from easyvibecoding/feat/linked-key-groups
feat: implement Linked Key Groups with sequential paste
2 parents 7ac1691 + 2360a90 commit 3a8fe27

22 files changed

Lines changed: 770 additions & 53 deletions

File tree

CLAUDE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ These are absolute rules — never violate them:
9797
- **Turbo navigation pre-hide**: `turbo:before-render` listener in pre-hide.ts hides key elements in incoming body BEFORE Turbo renders. Prevents GitHub PAT flash on partial page transition.
9898
- **OpenAI pre-hide scope**: preHideCSS must NOT include `td.api-key-token .api-key-token-value` — these are truncated previews (sk-...QngA) that never match full patterns, causing permanent hidden state.
9999
- **Toast duration**: 25 seconds (changed from 10s for better visibility during demos).
100+
- **Sequential paste pre-fetch**: `SequentialPasteEngine` pre-fetches ALL key values from Keychain before starting the paste sequence. This ensures Keychain auth dialogs (if any) appear upfront, not between ⌘V→Tab→⌘V steps. Phase 2 writes directly to `NSPasteboard`, bypassing `ClipboardEngine.copyToClipboard`.
101+
- **CGEvent modifier isolation**: When simulating ⌘V followed by Tab, the Tab `CGEvent` must explicitly set `flags = []` to clear residual Command modifier. Without this, the system interprets Tab as ⌘Tab (app switcher). Use `CGEventSource(stateID: .combinedSessionState)` for isolated event sources.
102+
- **Paste key shortcut**: Changed from `⌃⌥[1-9]` to `⌃⌥⌘[1-9]` to avoid conflicts with system/app shortcuts. All ⌃⌥⌘ shortcuts are consistent: D (demo), V (capture), [1-9] (paste).
100103

101104
## Documentation
102105

docs/01-product-spec/implementation-status.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
| ClipboardEngine || copy + autoClear + detectKeys 完成 |
2121
| MaskingCoordinator || isDemoMode / activeContext / pattern 匹配完成 |
2222
| IPCServer (WebSocket) || handshake / state_changed / pattern_cache_sync / toggle_demo_mode / nmh clientType |
23-
| HotkeyManager || `⌃⌥⌘D` toggle、`⌃⌥Space` hold 偵測、`⌃⌥[1-9]` paste、flagsChanged 監聽 |
23+
| HotkeyManager || `⌃⌥⌘D` toggle、`⌃⌥Space` hold 偵測、`⌃⌥[1-9]` paste、flagsChanged 監聽 |
2424
| Floating Toolbox (HUD) || NSPanel 浮動視窗、hold-to-search、Scheme B 鎖定、↑↓ 導航 |
2525
| ToolboxState (ViewModel) || 搜尋過濾、選取狀態、release/confirm/dismiss 邏輯 |
2626
| FloatingToolboxController || NSPanel 管理、游標定位、鎖定模式 makeKey |
@@ -33,7 +33,7 @@
3333
| 功能 | 對應 Spec 章節 | 優先順序 | 備註 |
3434
|------|--------------|---------|---------|
3535
| `⌃⌥⌘V` capture clipboard | Spec §4.4 || HotkeyManager 端尚未掛載 ClipboardEngine.detectKeys |
36-
| Linked Key Groups (sequential paste) | Spec §6.3 | | `LinkedGroup`/`GroupEntry` 結構未建立 |
36+
| ~~Linked Key Groups (sequential paste)~~ | Spec §6.3 | ~~~~ | `LinkedGroup`/`GroupEntry`/`SequentialPasteEngine` 完成、Settings UI 群組管理(CRUD)、`request_paste_group` IPC handler |
3737
| Shortcut conflict detection | Spec §4.4 || |
3838
| Import / Export vault | Spec §9.1 || |
3939

@@ -129,7 +129,7 @@
129129
### Phase 2: 剪貼簿 + 快捷鍵 ✅
130130
6. ~~ClipboardEngine~~
131131
7. ~~HotkeyManager(hold 偵測 + flagsChanged + 字元轉發)~~
132-
8. ~~Floating Toolbox HUD(NSPanel + hold-to-search + Scheme B 鎖定 + `⌃⌥[1-9]` paste)~~
132+
8. ~~Floating Toolbox HUD(NSPanel + hold-to-search + Scheme B 鎖定 + `⌃⌥[1-9]` paste)~~
133133

134134
### Phase 3: IPC + VS Code Extension ✅
135135
9. ~~IPCServer~~

docs/01-product-spec/roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
- macOS Menu Bar App (Swift/SwiftUI),Key 儲存基於 Keychain
88
- 展示模式切換與視覺指示
99
- 浮動工具箱,支援按住搜尋與方案 B 鎖定
10-
- 鍵盤快捷鍵:`⌃⌥Space``⌃⌥⌘D``⌃⌥[1-9]``⌃⌥⌘V`
10+
- 鍵盤快捷鍵:`⌃⌥Space``⌃⌥⌘D``⌃⌥[1-9]``⌃⌥⌘V`
1111
- VS Code Extension,使用 Decoration API 遮蔽
1212
- 雙層 Key 階層與手動 Key 輸入
1313
- 基本關聯 Key 群組(順序貼上)

docs/02-technical-architecture/swift-core-modules.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ DemoSafeApp (SwiftUI)
125125
|--------|------|------|
126126
| `⌃⌥Space` | `toggleToolbox()` | 顯示/隱藏浮動工具箱 |
127127
| `⌃⌥⌘D` | `toggleDemoMode()` | 切換展示/一般模式 |
128-
| `⌃⌥[1-9]` | `pasteKeyByIndex()` | 依快捷鍵索引貼上金鑰 |
128+
| `⌃⌥[1-9]` | `pasteKeyByIndex()` | 依快捷鍵索引貼上金鑰 |
129129
| `⌃⌥⌘V` | `captureClipboard()` | 掃描並儲存當前剪貼簿內容 |
130130

131131
### 按住偵測邏輯

docs/04-ui-ux/floating-toolbox.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
| 搜尋/過濾 | 繼續按住 + 輸入字元 | Key 清單即時過濾 |
1313
| 快速貼上(單一結果) | 僅剩 1 個結果時放開 | Key 貼入,工具箱消失 |
1414
| 從多個結果中選擇 | 放開 → 工具箱鎖定;用 `↑↓` + `Enter` | 按 Enter 貼入 Key,Esc 取消 |
15-
| 依編號直接貼上 |`⌃⌥[1-9]` | 立即貼入第 N 個 Key,無需工具箱 |
15+
| 依編號直接貼上 |`⌃⌥[1-9]` | 立即貼入第 N 個 Key,無需工具箱 |
1616

1717
## 鎖定行為(方案 B)
1818

docs/04-ui-ux/keyboard-shortcuts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
|------|-----------|---------|
77
| 切換浮動工具箱 | `⌃⌥Space` | 左手組合鍵,與應用程式衝突極少 |
88
| 切換展示模式 | `⌃⌥⌘D` | 三個修飾鍵防止意外觸發 |
9-
| 直接貼上第 N 個 Key | `⌃⌥[1-9]` | 已知 Key 位置的最快路徑 |
9+
| 直接貼上第 N 個 Key | `⌃⌥[1-9]` | 已知 Key 位置的最快路徑 |
1010
| 快速擷取剪貼簿內容 | `⌃⌥⌘V` | 貼上 + 自動解析入管理器 |
1111

1212
## 自訂設定

docs/04-ui-ux/smart-key-extraction.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,29 +136,32 @@ struct LinkedGroup: Codable, Identifiable {
136136
let id: UUID
137137
var label: String // 如 "AWS Production"
138138
var entries: [GroupEntry] // 有序的 Key 列表
139-
var pasteMode: PasteMode // .sequential 或 .fieldSelect
139+
var pasteMode: PasteMode // .sequential 或 .selectField
140+
var createdAt: Date
140141
}
141142

142143
struct GroupEntry: Codable {
143144
let keyId: UUID
144-
let fieldLabel: String // 如 "Access Key ID"、"Secret Key"
145+
var fieldLabel: String // 如 "Access Key ID"、"Secret Key"
145146
var sortOrder: Int
146147
}
147148

148149
enum PasteMode: String, Codable {
149-
case sequential // 按 Tab 自動依序貼入
150-
case fieldSelect // 顯示選單讓使用者選擇
150+
case selectField // 使用者選擇要貼上的欄位
151+
case sequential // 按 Tab 自動依序貼入
151152
}
152153
```
153154

154155
### 順序貼上模擬
155156

156157
```
157-
使用者觸發 LinkedGroup paste(⌃⌥[N] 對應群組)
158+
使用者觸發 LinkedGroup paste(⌃⌥[N] 對應群組)
158159
159-
1. 貼上 entries[0].value(Access Key ID)
160+
SequentialPasteEngine 預先從 Keychain 取出所有 key(避免中途跳認證窗)
161+
162+
1. 寫入 entries[0].value 到剪貼簿 → 模擬 ⌘V
160163
2. 模擬 Tab 鍵
161-
3. 貼上 entries[1].value(Secret Key)
164+
3. 寫入 entries[1].value 到剪貼簿 → 模擬 ⌘V
162165
163166
完成,兩個欄位同時填入
164167
```

docs/en/01-product-spec/implementation-status.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
| ClipboardEngine || copy + autoClear + detectKeys completed |
2121
| MaskingCoordinator || isDemoMode / activeContext / pattern matching completed |
2222
| IPCServer (WebSocket) || handshake / state_changed / pattern_cache_sync / toggle_demo_mode / nmh clientType |
23-
| HotkeyManager || `⌃⌥⌘D` toggle, `⌃⌥Space` hold detection, `⌃⌥[1-9]` paste, flagsChanged listener |
23+
| HotkeyManager || `⌃⌥⌘D` toggle, `⌃⌥Space` hold detection, `⌃⌥[1-9]` paste, flagsChanged listener |
2424
| Floating Toolbox (HUD) || NSPanel floating window, hold-to-search, Scheme B lock, ↑↓ navigation |
2525
| ToolboxState (ViewModel) || Search filtering, selection state, release/confirm/dismiss logic |
2626
| FloatingToolboxController || NSPanel management, cursor positioning, locked mode makeKey |
@@ -33,7 +33,7 @@
3333
| Feature | Spec Section | Priority | Notes |
3434
|---------|-------------|----------|---------|
3535
| `⌃⌥⌘V` capture clipboard | Spec §4.4 | Medium | HotkeyManager not yet wired to ClipboardEngine.detectKeys |
36-
| Linked Key Groups (sequential paste) | Spec §6.3 | Medium | `LinkedGroup`/`GroupEntry` structs not yet created |
36+
| ~~Linked Key Groups (sequential paste)~~ | Spec §6.3 | ~~Medium~~ | `LinkedGroup`/`GroupEntry`/`SequentialPasteEngine` complete, Settings UI group management (CRUD), `request_paste_group` IPC handler |
3737
| Shortcut conflict detection | Spec §4.4 | Low | |
3838
| Import / Export vault | Spec §9.1 | Low | |
3939

@@ -129,7 +129,7 @@ Per Spec §9 Roadmap:
129129
### Phase 2: Clipboard + Hotkeys ✅
130130
6. ~~ClipboardEngine~~
131131
7. ~~HotkeyManager (hold detection + flagsChanged + keystroke forwarding)~~
132-
8. ~~Floating Toolbox HUD (NSPanel + hold-to-search + Scheme B lock + `⌃⌥[1-9]` paste)~~
132+
8. ~~Floating Toolbox HUD (NSPanel + hold-to-search + Scheme B lock + `⌃⌥[1-9]` paste)~~
133133

134134
### Phase 3: IPC + VS Code Extension ✅
135135
9. ~~IPCServer~~

docs/en/01-product-spec/roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ The minimum viable product focuses on the **VS Code + Menu Bar** experience:
77
- macOS Menu Bar App (Swift/SwiftUI), Keychain-based key storage
88
- Demo mode toggle with visual indicator
99
- Floating toolbox with hold-to-search and Scheme B lock
10-
- Keyboard shortcuts: `⌃⌥Space`, `⌃⌥⌘D`, `⌃⌥[1-9]`, `⌃⌥⌘V`
10+
- Keyboard shortcuts: `⌃⌥Space`, `⌃⌥⌘D`, `⌃⌥[1-9]`, `⌃⌥⌘V`
1111
- VS Code Extension with Decoration API masking
1212
- Two-tier key hierarchy and manual key entry
1313
- Basic linked key groups (sequential paste)

docs/en/02-technical-architecture/swift-core-modules.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ Manages global keyboard shortcuts using `CGEvent.tapCreate` for system-level hot
125125
|--------|--------|-------------|
126126
| `⌃⌥Space` | `toggleToolbox()` | Show/hide floating toolbox |
127127
| `⌃⌥⌘D` | `toggleDemoMode()` | Toggle demo/normal mode |
128-
| `⌃⌥[1-9]` | `pasteKeyByIndex()` | Paste key by shortcut index |
128+
| `⌃⌥[1-9]` | `pasteKeyByIndex()` | Paste key by shortcut index |
129129
| `⌃⌥⌘V` | `captureClipboard()` | Scan and save current clipboard contents |
130130

131131
### Hold-to-Detect Logic

0 commit comments

Comments
 (0)