Skip to content

Commit 0a594b6

Browse files
committed
chore: version packages
1 parent 89d787a commit 0a594b6

File tree

8 files changed

+139
-30
lines changed

8 files changed

+139
-30
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# aicodeman
22

3+
## 0.5.9
4+
5+
### Patch Changes
6+
7+
- Mobile keyboard accessory bar: add configurable "Extended Keyboard Bar" setting (Settings > Display > Input) that toggles between simple mode (up/down arrows, /init, /clear, /compact, paste, dismiss) and extended mode (adds left/right arrows, Tab, Shift+Tab, Ctrl+O, Alt+Enter, Esc). Default is simple mode. Setting is device-specific (not synced to server).
8+
9+
Restyle dismiss button: muted steel-blue tone, fills remaining bar space via flex, larger tap target. Arrow buttons now blue.
10+
11+
Fix paste overlay visibility on mobile: dialog repositioned to top of screen (15vh from top) so the virtual keyboard doesn't cover it. Textarea enlarged for better usability.
12+
13+
(Also includes all v0.5.8 changes: case reorder/delete, XSS sanitization, auto-attach PTY on restart, mobile keyboard buttons, macOS installer fixes, terminal flicker fix, state store collision fix.)
14+
315
## 0.5.8
416

517
### Patch Changes

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ When user says "COM":
5252
4. **Sync CLAUDE.md version**: Update the `**Version**` line below to match the new version from `package.json`
5353
5. **Commit and deploy**: `git add -A && git commit -m "chore: version packages" && git push && npm run build && systemctl --user restart codeman-web`
5454
55-
**Version**: 0.5.8 (must match `package.json`)
55+
**Version**: 0.5.9 (must match `package.json`)
5656
5757
## Project Overview
5858

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "aicodeman",
3-
"version": "0.5.8",
3+
"version": "0.5.9",
44
"description": "The missing control plane for AI coding agents - run 20 autonomous agents with real-time monitoring and session persistence",
55
"type": "module",
66
"main": "dist/index.js",

src/web/public/app.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,9 @@ class CodemanApp {
523523
SwipeHandler.init();
524524
VoiceInput.init();
525525
KeyboardAccessoryBar.init();
526+
// Apply keyboard bar mode from settings
527+
const _kbSettings = this.loadAppSettingsFromStorage();
528+
if (_kbSettings.extendedKeyboardBar) KeyboardAccessoryBar.setMode('extended');
526529
this.applyHeaderVisibilitySettings();
527530
this.applyTabWrapSettings();
528531
this.applyMonitorVisibility();

src/web/public/index.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,17 @@ <h3>App Settings</h3>
892892
</label>
893893
</div>
894894

895+
<div class="settings-item settings-item-multiline" title="Show additional buttons (Tab, Shift+Tab, Ctrl+O, Esc, Alt+Enter, left/right arrows) in the mobile keyboard accessory bar.">
896+
<div class="settings-item-text">
897+
<span class="settings-item-label">Extended Keyboard Bar</span>
898+
<span class="settings-item-desc">Extra keys: Tab, Esc, arrows, Ctrl+O</span>
899+
</div>
900+
<label class="switch switch-sm">
901+
<input type="checkbox" id="appSettingsExtendedKeyboardBar">
902+
<span class="slider"></span>
903+
</label>
904+
</div>
905+
895906
<!-- Header Displays Section -->
896907
<div class="settings-section-header">Header Displays</div>
897908
<div class="settings-item" title="Show A-/A+ font size buttons in header">

src/web/public/keyboard-accessory.js

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Defines two exports:
55
*
66
* - KeyboardAccessoryBar (singleton object) — Quick action buttons shown above the virtual
7-
* keyboard on mobile: Esc, arrow up/down, Tab, Shift+Tab, Ctrl+O, /init, /clear, /compact, paste, and dismiss.
7+
* keyboard on mobile: arrow up/down, /init, /clear, /compact, paste, and dismiss.
88
* Destructive actions (/clear, /compact) require double-tap confirmation (2s amber state).
99
* Commands are sent as text + Enter separately for Ink compatibility.
1010
* Only initializes on touch devices (MobileDetection.isTouchDevice guard).
@@ -33,16 +33,37 @@
3333
*/
3434
const KeyboardAccessoryBar = {
3535
element: null,
36+
_mode: 'simple', // 'simple' or 'extended'
3637

37-
/** Create and inject the accessory bar */
38-
init() {
39-
// Only on mobile
40-
if (!MobileDetection.isTouchDevice()) return;
38+
/** HTML for simple mode: arrows, commands, paste, dismiss */
39+
_simpleButtons: `
40+
<button class="accessory-btn accessory-btn-arrow" data-action="scroll-up" title="Arrow up">
41+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
42+
<path d="M5 15l7-7 7 7"/>
43+
</svg>
44+
</button>
45+
<button class="accessory-btn accessory-btn-arrow" data-action="scroll-down" title="Arrow down">
46+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
47+
<path d="M19 9l-7 7-7-7"/>
48+
</svg>
49+
</button>
50+
<button class="accessory-btn" data-action="init" title="/init">/init</button>
51+
<button class="accessory-btn" data-action="clear" title="/clear">/clear</button>
52+
<button class="accessory-btn" data-action="compact" title="/compact">/compact</button>
53+
<button class="accessory-btn" data-action="paste" title="Paste from clipboard">
54+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
55+
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>
56+
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"/>
57+
</svg>
58+
</button>
59+
<button class="accessory-btn accessory-btn-dismiss" data-action="dismiss" title="Dismiss keyboard">
60+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
61+
<path d="M19 9l-7 7-7-7"/>
62+
</svg>
63+
</button>`,
4164

42-
// Create accessory bar element
43-
this.element = document.createElement('div');
44-
this.element.className = 'keyboard-accessory-bar';
45-
this.element.innerHTML = `
65+
/** HTML for extended mode: all keys including arrows, Tab, Esc, etc. */
66+
_extendedButtons: `
4667
<button class="accessory-btn accessory-btn-arrow" data-action="scroll-up" title="Arrow up">
4768
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
4869
<path d="M5 15l7-7 7 7"/>
@@ -77,12 +98,21 @@ const KeyboardAccessoryBar = {
7798
<button class="accessory-btn" data-action="init" title="/init">/init</button>
7899
<button class="accessory-btn" data-action="clear" title="/clear">/clear</button>
79100
<button class="accessory-btn" data-action="compact" title="/compact">/compact</button>
80-
<button class="accessory-btn accessory-btn-arrow" data-action="dismiss" title="Dismiss keyboard">
81-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
101+
<button class="accessory-btn accessory-btn-dismiss" data-action="dismiss" title="Dismiss keyboard">
102+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
82103
<path d="M19 9l-7 7-7-7"/>
83104
</svg>
84-
</button>
85-
`;
105+
</button>`,
106+
107+
/** Create and inject the accessory bar */
108+
init() {
109+
// Only on mobile
110+
if (!MobileDetection.isTouchDevice()) return;
111+
112+
// Create accessory bar element
113+
this.element = document.createElement('div');
114+
this.element.className = 'keyboard-accessory-bar';
115+
this.element.innerHTML = this._simpleButtons;
86116

87117
// Add click handlers — preventDefault stops event from reaching terminal
88118
this.element.addEventListener('click', (e) => {
@@ -95,7 +125,8 @@ const KeyboardAccessoryBar = {
95125
this.handleAction(action, btn);
96126

97127
// Refocus terminal so keyboard stays open (tap blurs terminal → keyboard dismisses → toolbar shifts)
98-
if ((action === 'scroll-up' || action === 'scroll-down' || action === 'arrow-left' || action === 'arrow-right' || action === 'tab' || action === 'shift-tab' || action === 'ctrl-o' || action === 'opt-enter' || action === 'esc') ||
128+
const refocusActions = new Set(['scroll-up', 'scroll-down', 'arrow-left', 'arrow-right', 'tab', 'shift-tab', 'ctrl-o', 'opt-enter', 'esc']);
129+
if (refocusActions.has(action) ||
99130
((action === 'clear' || action === 'compact') && this._confirmAction)) {
100131
if (typeof app !== 'undefined' && app.terminal) {
101132
app.terminal.focus();
@@ -110,6 +141,14 @@ const KeyboardAccessoryBar = {
110141
}
111142
},
112143

144+
/** Switch between 'simple' and 'extended' button layouts */
145+
setMode(mode) {
146+
if (mode === this._mode || !this.element) return;
147+
this._mode = mode;
148+
this.clearConfirm();
149+
this.element.innerHTML = mode === 'extended' ? this._extendedButtons : this._simpleButtons;
150+
},
151+
113152
_confirmTimer: null,
114153
_confirmAction: null,
115154

src/web/public/mobile.css

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -937,13 +937,33 @@ html.mobile-init .file-browser-panel {
937937

938938
.accessory-btn-arrow {
939939
padding: 6px 10px;
940-
background: #1e3a5f;
941-
border-color: rgba(59, 130, 246, 0.3);
942-
color: #93c5fd;
940+
background: #2563eb;
941+
border-color: rgba(59, 130, 246, 0.5);
942+
color: #fff;
943943
}
944944

945945
.accessory-btn-arrow:active {
946+
background: #1d4ed8;
947+
}
948+
949+
.accessory-btn-dismiss {
950+
margin-left: auto;
951+
flex: 1 1 0;
952+
max-width: 100px;
953+
padding: 10px 8px;
946954
background: #2563eb;
955+
border-color: rgba(59, 130, 246, 0.5);
956+
color: #fff;
957+
font-weight: 600;
958+
}
959+
960+
.accessory-btn-dismiss svg {
961+
width: 22px;
962+
height: 22px;
963+
}
964+
965+
.accessory-btn-dismiss:active {
966+
background: #1d4ed8;
947967
}
948968

949969
/* Voice preview — positioned above accessory bar on mobile */
@@ -975,9 +995,9 @@ html.mobile-init .file-browser-panel {
975995
background: rgba(0, 0, 0, 0.6);
976996
z-index: 10000;
977997
display: flex;
978-
align-items: flex-end;
998+
align-items: flex-start;
979999
justify-content: center;
980-
padding-bottom: env(safe-area-inset-bottom, 12px);
1000+
padding-top: 15vh;
9811001
}
9821002

9831003
.paste-dialog {
@@ -987,13 +1007,12 @@ html.mobile-init .file-browser-panel {
9871007
padding: 12px;
9881008
width: calc(100% - 24px);
9891009
max-width: 400px;
990-
margin-bottom: 8px;
9911010
}
9921011

9931012
.paste-textarea {
9941013
width: 100%;
995-
min-height: 60px;
996-
max-height: 120px;
1014+
min-height: 80px;
1015+
max-height: 200px;
9971016
background: var(--bg-primary, #0d0d14);
9981017
color: var(--text-primary, #e0e0e0);
9991018
border: 1px solid var(--border-color, #444);
@@ -2104,13 +2123,33 @@ html.mobile-init .file-browser-panel {
21042123

21052124
.accessory-btn-arrow {
21062125
padding: 6px 10px;
2107-
background: #1e3a5f;
2108-
border-color: rgba(59, 130, 246, 0.3);
2109-
color: #93c5fd;
2126+
background: #2563eb;
2127+
border-color: rgba(59, 130, 246, 0.5);
2128+
color: #fff;
21102129
}
21112130

21122131
.accessory-btn-arrow:active {
2113-
background: #2563eb;
2132+
background: #1d4ed8;
2133+
}
2134+
2135+
.accessory-btn-dismiss {
2136+
margin-left: auto;
2137+
flex: 1 1 0;
2138+
max-width: 80px;
2139+
padding: 10px 8px;
2140+
background: #334d6e;
2141+
border-color: rgba(100, 150, 200, 0.4);
2142+
color: #c0d4e8;
2143+
font-weight: 600;
2144+
}
2145+
2146+
.accessory-btn-dismiss svg {
2147+
width: 20px;
2148+
height: 20px;
2149+
}
2150+
2151+
.accessory-btn-dismiss:active {
2152+
background: #3d5f85;
21142153
}
21152154

21162155
/* ============================================================================

src/web/public/settings-ui.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ Object.assign(CodemanApp.prototype, {
319319
this.loadTunnelStatus();
320320
document.getElementById('appSettingsLocalEcho').checked = settings.localEchoEnabled ?? MobileDetection.isTouchDevice();
321321
document.getElementById('appSettingsCjkInput').checked = settings.cjkInputEnabled ?? false;
322+
document.getElementById('appSettingsExtendedKeyboardBar').checked = settings.extendedKeyboardBar ?? false;
322323
document.getElementById('appSettingsTabTwoRows').checked = settings.tabTwoRows ?? defaults.tabTwoRows ?? false;
323324
// Claude CLI settings
324325
const claudeModeSelect = document.getElementById('appSettingsClaudeMode');
@@ -1125,6 +1126,7 @@ Object.assign(CodemanApp.prototype, {
11251126
tunnelEnabled: document.getElementById('appSettingsTunnelEnabled').checked,
11261127
localEchoEnabled: document.getElementById('appSettingsLocalEcho').checked,
11271128
cjkInputEnabled: document.getElementById('appSettingsCjkInput').checked,
1129+
extendedKeyboardBar: document.getElementById('appSettingsExtendedKeyboardBar').checked,
11281130
tabTwoRows: document.getElementById('appSettingsTabTwoRows').checked,
11291131
// Claude CLI settings
11301132
claudeMode: document.getElementById('appSettingsClaudeMode').value,
@@ -1245,9 +1247,12 @@ Object.assign(CodemanApp.prototype, {
12451247
// Apply CJK input visibility immediately
12461248
this._updateCjkInputState();
12471249

1250+
// Apply keyboard bar mode
1251+
KeyboardAccessoryBar.setMode(settings.extendedKeyboardBar ? 'extended' : 'simple');
1252+
12481253
// Save to server (includes notification prefs for cross-browser persistence)
12491254
// Strip device-specific keys — localEchoEnabled/cjkInputEnabled are per-platform
1250-
const { localEchoEnabled: _leo, cjkInputEnabled: _cjk, ...serverSettings } = settings;
1255+
const { localEchoEnabled: _leo, cjkInputEnabled: _cjk, extendedKeyboardBar: _ekb, ...serverSettings } = settings;
12511256
try {
12521257
await this._apiPut('/api/settings', { ...serverSettings, notificationPreferences: notifPrefsToSave, voiceSettings });
12531258

@@ -1631,7 +1636,7 @@ Object.assign(CodemanApp.prototype, {
16311636
const displayKeys = new Set([
16321637
'showFontControls', 'showSystemStats', 'showTokenCount', 'showCost',
16331638
'showMonitor', 'showProjectInsights', 'showFileBrowser', 'showSubagents',
1634-
'subagentActiveTabOnly', 'tabTwoRows', 'localEchoEnabled', 'cjkInputEnabled',
1639+
'subagentActiveTabOnly', 'tabTwoRows', 'localEchoEnabled', 'cjkInputEnabled', 'extendedKeyboardBar',
16351640
]);
16361641
// Merge settings: non-display keys always sync from server,
16371642
// display keys only seed from server when localStorage has no value

0 commit comments

Comments
 (0)