ai-or-die 0.1.44 → 0.1.45
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/.github/workflows/ci.yml +36 -0
- package/package.json +1 -1
- package/src/public/app.js +21 -5
- package/src/public/components/extra-keys.css +2 -2
- package/src/public/components/tabs.css +2 -0
- package/src/public/mobile.css +3 -2
- package/src/public/session-manager.js +3 -3
- package/src/server.js +2 -0
package/.github/workflows/ci.yml
CHANGED
|
@@ -471,6 +471,42 @@ jobs:
|
|
|
471
471
|
playwright-report/
|
|
472
472
|
retention-days: 14
|
|
473
473
|
|
|
474
|
+
test-browser-mobile-journeys:
|
|
475
|
+
runs-on: ${{ matrix.os }}
|
|
476
|
+
needs: test
|
|
477
|
+
timeout-minutes: 12
|
|
478
|
+
strategy:
|
|
479
|
+
fail-fast: false
|
|
480
|
+
matrix:
|
|
481
|
+
os: [ubuntu-latest, windows-latest]
|
|
482
|
+
steps:
|
|
483
|
+
- uses: actions/checkout@v4
|
|
484
|
+
- uses: actions/setup-node@v4
|
|
485
|
+
with:
|
|
486
|
+
node-version: '22'
|
|
487
|
+
cache: 'npm'
|
|
488
|
+
- run: npm ci
|
|
489
|
+
- name: Cache Playwright browsers
|
|
490
|
+
uses: actions/cache@v4
|
|
491
|
+
with:
|
|
492
|
+
path: |
|
|
493
|
+
~/.cache/ms-playwright
|
|
494
|
+
~/AppData/Local/ms-playwright
|
|
495
|
+
key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
|
|
496
|
+
- name: Install Playwright browsers
|
|
497
|
+
run: npx playwright install chromium --with-deps
|
|
498
|
+
- name: Run mobile journey tests
|
|
499
|
+
run: npx playwright test --config e2e/playwright.config.js --project mobile-journeys
|
|
500
|
+
- name: Upload Playwright report
|
|
501
|
+
uses: actions/upload-artifact@v4
|
|
502
|
+
if: ${{ !cancelled() }}
|
|
503
|
+
with:
|
|
504
|
+
name: playwright-mobile-journeys-${{ matrix.os }}
|
|
505
|
+
path: |
|
|
506
|
+
e2e/test-results/
|
|
507
|
+
playwright-report/
|
|
508
|
+
retention-days: 14
|
|
509
|
+
|
|
474
510
|
build-binary:
|
|
475
511
|
runs-on: ${{ matrix.os }}
|
|
476
512
|
timeout-minutes: 12
|
package/package.json
CHANGED
package/src/public/app.js
CHANGED
|
@@ -674,11 +674,16 @@ class ClaudeCodeWebInterface {
|
|
|
674
674
|
}
|
|
675
675
|
|
|
676
676
|
_setupExtraKeys() {
|
|
677
|
-
if (!this.isMobile ||
|
|
677
|
+
if (!this.isMobile || typeof ExtraKeys === 'undefined') return;
|
|
678
678
|
|
|
679
679
|
this.extraKeys = new ExtraKeys({ app: this });
|
|
680
680
|
this._keyboardOpen = false;
|
|
681
681
|
|
|
682
|
+
// Browsers without visualViewport (Firefox Android, Samsung Internet):
|
|
683
|
+
// Initialize extra-keys but skip viewport-based keyboard detection.
|
|
684
|
+
// The extra-keys bar is still usable via manual show/hide.
|
|
685
|
+
if (!window.visualViewport) return;
|
|
686
|
+
|
|
682
687
|
// Thrashing detection: if >3 resize events in 500ms, fall back to fixed threshold
|
|
683
688
|
const resizeTimestamps = [];
|
|
684
689
|
let useFallbackThreshold = false;
|
|
@@ -1477,6 +1482,9 @@ class ClaudeCodeWebInterface {
|
|
|
1477
1482
|
if (this._reconnecting) return;
|
|
1478
1483
|
this._reconnecting = true;
|
|
1479
1484
|
this.disconnect();
|
|
1485
|
+
// Reset overlay flag so session_joined can show start prompt if terminal
|
|
1486
|
+
// exited during the disconnect (fixes stuck blank screen after reconnect)
|
|
1487
|
+
this._overlayExplicitlyHidden = false;
|
|
1480
1488
|
// Reset flow control state so stale pause signals aren't sent on new connection
|
|
1481
1489
|
this._outputPaused = false;
|
|
1482
1490
|
this._pendingCallbacks = 0;
|
|
@@ -1494,7 +1502,10 @@ class ClaudeCodeWebInterface {
|
|
|
1494
1502
|
}
|
|
1495
1503
|
setTimeout(() => {
|
|
1496
1504
|
try {
|
|
1497
|
-
|
|
1505
|
+
const connectTimeout = new Promise((_, reject) =>
|
|
1506
|
+
setTimeout(() => reject(new Error('Connection timeout')), 10000)
|
|
1507
|
+
);
|
|
1508
|
+
Promise.race([this.connect(), connectTimeout])
|
|
1498
1509
|
.catch(err => console.error('Reconnection failed:', err))
|
|
1499
1510
|
.finally(() => { this._reconnecting = false; });
|
|
1500
1511
|
} catch (err) {
|
|
@@ -3694,6 +3705,11 @@ class ClaudeCodeWebInterface {
|
|
|
3694
3705
|
this.pendingJoinResolve = resolve;
|
|
3695
3706
|
this.pendingJoinSessionId = sessionId;
|
|
3696
3707
|
|
|
3708
|
+
// Reset overlay flag before joining a new session so that
|
|
3709
|
+
// session_joined can correctly show/hide the overlay based on
|
|
3710
|
+
// the NEW session's state, not a stale flag from the previous tab.
|
|
3711
|
+
this._overlayExplicitlyHidden = false;
|
|
3712
|
+
|
|
3697
3713
|
// Send the join request
|
|
3698
3714
|
this.send({ type: 'join_session', sessionId });
|
|
3699
3715
|
|
|
@@ -4012,7 +4028,7 @@ class ClaudeCodeWebInterface {
|
|
|
4012
4028
|
// Container is already visible by default
|
|
4013
4029
|
|
|
4014
4030
|
// Check if mobile screen
|
|
4015
|
-
const isMobile = window.innerWidth <=
|
|
4031
|
+
const isMobile = window.innerWidth <= 820;
|
|
4016
4032
|
const isSmallMobile = window.innerWidth <= 480;
|
|
4017
4033
|
|
|
4018
4034
|
// Format tokens (K/M notation)
|
|
@@ -4152,7 +4168,7 @@ class ClaudeCodeWebInterface {
|
|
|
4152
4168
|
if (totalTokens > 0) {
|
|
4153
4169
|
const opusPercent = (opusTokens / totalTokens) * 100;
|
|
4154
4170
|
const sonnetPercent = (sonnetTokens / totalTokens) * 100;
|
|
4155
|
-
const isMobile = window.innerWidth <=
|
|
4171
|
+
const isMobile = window.innerWidth <= 820;
|
|
4156
4172
|
|
|
4157
4173
|
// Use short names on mobile, full names on desktop
|
|
4158
4174
|
const opusName = isMobile ? 'O' : 'Opus';
|
|
@@ -4175,7 +4191,7 @@ class ClaudeCodeWebInterface {
|
|
|
4175
4191
|
}
|
|
4176
4192
|
} else {
|
|
4177
4193
|
// No active session or expired session - show zeros
|
|
4178
|
-
const isMobile = window.innerWidth <=
|
|
4194
|
+
const isMobile = window.innerWidth <= 820;
|
|
4179
4195
|
|
|
4180
4196
|
document.getElementById('usageTitle').textContent = '0h 0m';
|
|
4181
4197
|
document.getElementById('usageTokens').textContent = isMobile ? '0%' : '0';
|
package/src/public/mobile.css
CHANGED
|
@@ -328,7 +328,7 @@
|
|
|
328
328
|
padding: 0;
|
|
329
329
|
border-width: 0;
|
|
330
330
|
overflow: hidden;
|
|
331
|
-
transition: opacity 0.2s ease, height 0.2s ease;
|
|
331
|
+
transition: opacity 0.2s ease, height 0.2s ease, padding 0.2s ease, border-width 0.2s ease;
|
|
332
332
|
}
|
|
333
333
|
body.keyboard-open .session-tabs-bar {
|
|
334
334
|
height: 0;
|
|
@@ -336,7 +336,8 @@
|
|
|
336
336
|
overflow: hidden;
|
|
337
337
|
padding: 0;
|
|
338
338
|
border-width: 0;
|
|
339
|
-
|
|
339
|
+
opacity: 0;
|
|
340
|
+
transition: opacity 0.2s ease, height 0.2s ease, padding 0.2s ease, border-width 0.2s ease;
|
|
340
341
|
}
|
|
341
342
|
body.keyboard-open #app {
|
|
342
343
|
padding-bottom: 0 !important;
|
|
@@ -479,7 +479,7 @@ class SessionTabManager {
|
|
|
479
479
|
}
|
|
480
480
|
|
|
481
481
|
updateTabOverflow() {
|
|
482
|
-
const isMobile = window.innerWidth <=
|
|
482
|
+
const isMobile = window.innerWidth <= 820;
|
|
483
483
|
const overflowWrapper = document.getElementById('tabOverflowWrapper');
|
|
484
484
|
const overflowCount = document.querySelector('.tab-overflow-count');
|
|
485
485
|
|
|
@@ -647,7 +647,7 @@ class SessionTabManager {
|
|
|
647
647
|
});
|
|
648
648
|
|
|
649
649
|
// Reorder tabs based on the initial timestamps (mobile only)
|
|
650
|
-
if (window.innerWidth <=
|
|
650
|
+
if (window.innerWidth <= 820) {
|
|
651
651
|
this.reorderTabsByLastAccessed();
|
|
652
652
|
}
|
|
653
653
|
|
|
@@ -808,7 +808,7 @@ class SessionTabManager {
|
|
|
808
808
|
this.updateTabHistory(sessionId);
|
|
809
809
|
}
|
|
810
810
|
|
|
811
|
-
if (window.innerWidth <=
|
|
811
|
+
if (window.innerWidth <= 820) {
|
|
812
812
|
const tabIndex = this.getOrderedTabIds().indexOf(sessionId);
|
|
813
813
|
if (tabIndex >= 2) this.reorderTabsByLastAccessed();
|
|
814
814
|
}
|
package/src/server.js
CHANGED
|
@@ -126,6 +126,7 @@ class ClaudeCodeWebServer {
|
|
|
126
126
|
for (const [id, session] of this.claudeSessions) {
|
|
127
127
|
if (!session.active && session.connections.size === 0 && new Date(session.lastActivity || session.created).getTime() < sevenDaysAgo) {
|
|
128
128
|
this.claudeSessions.delete(id);
|
|
129
|
+
this.activityBroadcastTimestamps.delete(id);
|
|
129
130
|
this.sessionStore.markDirty();
|
|
130
131
|
}
|
|
131
132
|
}
|
|
@@ -1795,6 +1796,7 @@ class ClaudeCodeWebServer {
|
|
|
1795
1796
|
currentSession.agent = null;
|
|
1796
1797
|
this.sessionStore.markDirty();
|
|
1797
1798
|
}
|
|
1799
|
+
this.activityBroadcastTimestamps.delete(sessionId);
|
|
1798
1800
|
this.broadcastToSession(sessionId, { type: 'error', message: error.message });
|
|
1799
1801
|
this.broadcastSessionActivity(sessionId, 'session_error');
|
|
1800
1802
|
},
|