dsh-apk-vm 0.6.1 → 0.6.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.2
4
+
5
+ Sidebar usability.
6
+
7
+ ### Added
8
+
9
+ - **Expand / restore button** in the VM panel header. It turns the panel into a
10
+ full-window overlay so a narrow `dsh-better-sidebar` tab can show a large phone screen;
11
+ press Escape or click the button again to restore the sidebar layout.
12
+ - The overlay hides the APK/debug aside, keeps the H.264 stream and input controls, and
13
+ reuses the existing canvas/WebSocket session (no second stream).
14
+
3
15
  ## 0.6.1
4
16
 
5
17
  Network panel completeness.
package/README.md CHANGED
@@ -8,6 +8,26 @@
8
8
 
9
9
  **Run a real Android APK inside a local, rooted, open-source Android VM and preview it in the DeepSeek Harness sidebar — streamed as H.264/WebCodecs video at up to 60 fps.**
10
10
 
11
+ <p align="center">
12
+ <a href="docs/screenshot-panel.png">
13
+ <img src="docs/screenshot-panel.png" alt="APK Virtual Machine panel with a live H.264 Android screen in DeepSeek Harness" width="820">
14
+ </a>
15
+ </p>
16
+ <p align="center"><sub>Real panel capture: rooted Android 14 guest, live H.264 stream, input controls and installed-app tools — no mockup.</sub></p>
17
+ <p align="center">
18
+ <code>dsh plugin --profile web add dsh-apk-vm</code>
19
+ &nbsp;·&nbsp;
20
+ <a href="examples/README.md">reproducible demo</a>
21
+ </p>
22
+
23
+ **Why it is useful**
24
+
25
+ - **Sidebar-first Android** — install and use an APK without opening a separate emulator window.
26
+ - **Real, low-latency stream** — H.264/WebCodecs up to 60 fps with tap, swipe, key and text input.
27
+ - **Agent-native** — `apk_vm` tools, a live UI Inspector, copy-ready selectors and record/replay flows.
28
+ - **Local and inspectable** — open-source AOSP emulator, rooted debug API, network/storage controls, no telemetry.
29
+ - **Expandable viewer** — turn the narrow sidebar panel into a full-window VM with one click; Escape restores it.
30
+
11
31
  This repository contains the static DSH plugin `dsh-apk-vm`. It adds a first-class sidebar
12
32
  entry ("APK Virtual Machine" / "APK 虚拟机") whose main panel boots an AOSP Android Emulator,
13
33
  installs an APK into the guest, streams the guest display into the panel, and forwards
@@ -24,7 +44,7 @@ same-origin, loopback-only debug HTTP API and an `apk_vm` Agent tool.
24
44
  > 当前 **Windows x64 与 Linux x86_64(headless)为端到端已验证平台**;macOS 仅做探测/CI
25
45
  > 覆盖,详见 `docs/LINUX-E2E.md`。
26
46
 
27
- **Status:** `0.6.1` · Apache-2.0 · no npm runtime dependencies · no build step.
47
+ **Status:** `0.6.2` · Apache-2.0 · no npm runtime dependencies · no build step.
28
48
 
29
49
  This is an open-source DSH plugin published on npm as **`dsh-apk-vm`**. Repository:
30
50
  [github.com/yuxiaole-bili/dsh-apk-vm](https://github.com/yuxiaole-bili/dsh-apk-vm).
package/client.js CHANGED
@@ -103,6 +103,8 @@ window.__ModuleLoader__.load({
103
103
  'action.installLaunch': 'Install & launch',
104
104
  'action.dismiss': 'Dismiss',
105
105
  'action.openSidebar': 'Open in side bar',
106
+ 'action.expand': 'Expand',
107
+ 'action.restore': 'Exit expanded',
106
108
  'a11y.refresh': 'Refresh VM state',
107
109
  'a11y.retry': 'Retry the request',
108
110
  'a11y.openSidebar': 'Open the APK VM in dsh-better-sidebar',
@@ -336,6 +338,8 @@ window.__ModuleLoader__.load({
336
338
  'action.installLaunch': '安装并启动',
337
339
  'action.dismiss': '关闭',
338
340
  'action.openSidebar': '在侧栏打开',
341
+ 'action.expand': '放大',
342
+ 'action.restore': '退出放大',
339
343
  'a11y.refresh': '刷新虚拟机状态',
340
344
  'a11y.retry': '重试请求',
341
345
  'a11y.openSidebar': '在 dsh-better-sidebar 中打开 APK 虚拟机',
@@ -1064,7 +1068,17 @@ window.__ModuleLoader__.load({
1064
1068
  '.apkvm-embedded .apkvm-phonewrap{flex:0 0 auto;min-height:320px}' +
1065
1069
  '.apkvm-embedded .apkvm-controls{max-width:none}' +
1066
1070
  '@media (max-width:900px){.apkvm-header{flex-wrap:wrap}}' +
1067
- '.apkvm-embedded .apkvm-header{flex-wrap:wrap}';
1071
+ '.apkvm-embedded .apkvm-header{flex-wrap:wrap}' +
1072
+ '.apkvm-page.apkvm-maximized{position:fixed;inset:0;z-index:2147483000;width:100vw;height:100vh;background:var(--dsw-alias-bg-base);box-shadow:0 0 0 1px var(--dsw-alias-border-l2)}' +
1073
+ '.apkvm-page.apkvm-maximized .apkvm-header{flex:0 0 auto;background:var(--dsw-alias-bg-base)}' +
1074
+ '.apkvm-page.apkvm-maximized .apkvm-body{flex:1 1 auto;min-height:0;padding:10px 16px 14px;gap:10px;overflow:hidden;flex-direction:row}' +
1075
+ '.apkvm-page.apkvm-maximized .apkvm-aside{display:none}' +
1076
+ '.apkvm-page.apkvm-maximized .apkvm-stage{flex:1 1 auto;min-height:0;max-height:none}' +
1077
+ '.apkvm-page.apkvm-maximized .apkvm-phonewrap{flex:1 1 auto;min-height:0;padding:0}' +
1078
+ '.apkvm-page.apkvm-maximized .apkvm-phone{height:100%;max-height:calc(100vh - 150px);padding:6px;border-radius:22px}' +
1079
+ '.apkvm-page.apkvm-maximized .apkvm-screen{height:100%;max-height:calc(100vh - 170px);border-radius:16px}' +
1080
+ '.apkvm-page.apkvm-maximized .apkvm-controls{max-width:760px}' +
1081
+ '.apkvm-page.apkvm-maximized .apkvm-stagehint{max-width:760px}';
1068
1082
 
1069
1083
  /* ------------------------------------------------------------------ *
1070
1084
  * Render-error boundary: an unexpected exception inside the panel keeps
@@ -1373,6 +1387,10 @@ window.__ModuleLoader__.load({
1373
1387
  var canvasRef = React.useRef(null);
1374
1388
  var decoderRef = React.useRef(null);
1375
1389
  var wsRef = React.useRef(null);
1390
+ var pageRef = React.useRef(null);
1391
+ var maximizedState = React.useState(false);
1392
+ var isMaximized = maximizedState[0];
1393
+ var setIsMaximized = maximizedState[1];
1376
1394
 
1377
1395
  /* ---- derived snapshot values --------------------------------- */
1378
1396
  var vmInfo = snapshot ? snapshot.vm : null;
@@ -1528,6 +1546,21 @@ window.__ModuleLoader__.load({
1528
1546
  if (ready) loadNetwork();
1529
1547
  }, [ready, activeInstance]);
1530
1548
 
1549
+ // Escape leaves the expanded VM view; the expand button is inside the
1550
+ // full-screen overlay too, so mouse-only users are never trapped.
1551
+ React.useEffect(function () {
1552
+ if (!isMaximized || typeof document === 'undefined' || typeof document.addEventListener !== 'function') {
1553
+ return undefined;
1554
+ }
1555
+ function onKeyDown(event) {
1556
+ if (event && event.key === 'Escape') setIsMaximized(false);
1557
+ }
1558
+ document.addEventListener('keydown', onKeyDown);
1559
+ return function () {
1560
+ document.removeEventListener('keydown', onKeyDown);
1561
+ };
1562
+ }, [isMaximized]);
1563
+
1531
1564
  // Track document visibility so the frame stream pauses when hidden.
1532
1565
  React.useEffect(function () {
1533
1566
  if (typeof document === 'undefined' || typeof document.addEventListener !== 'function') {
@@ -4516,6 +4549,17 @@ window.__ModuleLoader__.load({
4516
4549
  (videoMode === 'h264' ? T('fps.mode.h264') : T('fps.mode.png'))
4517
4550
  ),
4518
4551
  primaryAction,
4552
+ actionBtn(T(isMaximized ? 'action.restore' : 'action.expand'), {
4553
+ key: 'maximize',
4554
+ small: true,
4555
+ icon: h('span', { 'aria-hidden': 'true', style: { fontSize: '14px', lineHeight: '14px' } }, isMaximized ? '⛜' : '⛶'),
4556
+ ariaLabel: T(isMaximized ? 'action.restore' : 'action.expand'),
4557
+ onClick: function () {
4558
+ setIsMaximized(function (value) {
4559
+ return !value;
4560
+ });
4561
+ },
4562
+ }),
4519
4563
  !embedded && sidebarService
4520
4564
  ? actionBtn(T('action.openSidebar'), {
4521
4565
  key: 'open-sidebar',
@@ -4697,7 +4741,8 @@ window.__ModuleLoader__.load({
4697
4741
  return h(
4698
4742
  'div',
4699
4743
  {
4700
- className: 'apkvm-page' + (embedded ? ' apkvm-embedded' : ''),
4744
+ className: 'apkvm-page' + (embedded ? ' apkvm-embedded' : '') + (isMaximized ? ' apkvm-maximized' : ''),
4745
+ ref: pageRef,
4701
4746
  onDragEnter: onPageDragEnter,
4702
4747
  onDragOver: onPageDragOver,
4703
4748
  onDragLeave: onPageDragLeave,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-apk-vm",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "type": "module",
5
5
  "description": "Local AOSP Android VM for DeepSeek Harness: preview rooted APKs at up to 60 fps, automate UIAutomator flows, and give each Agent an isolated VM.",
6
6
  "license": "Apache-2.0",