the-android-mcp 3.24.0 → 3.24.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.md CHANGED
@@ -40,11 +40,14 @@ sequenceDiagram
40
40
 
41
41
  ## Web UI v3 (Local 50000)
42
42
 
43
- The local web cockpit is now designed for complete beginners first, with advanced controls hidden behind an explicit toggle.
43
+ The local web cockpit is now English-first and beginner-first, with advanced controls hidden behind an explicit toggle.
44
44
 
45
45
  - URL: `http://127.0.0.1:50000`
46
46
  - Start command: `the-android-mcp-web-ui --serve --host 127.0.0.1 --port 50000`
47
- - UX direction: plain-language actions, large guided cards, futuristic gradients, and visual mission feedback.
47
+ - UX direction: plain-language actions, large guided cards, and clearer operational feedback.
48
+ - Structure: `Simple Mode` for daily actions, `Expert Area` for full controls.
49
+ - Expert Area: large control sets are grouped into collapsible modules with `Expand All Modules` / `Collapse All Modules`.
50
+ - Startup safety: schedule auto-resume is disabled by default; enable with `THE_ANDROID_MCP_RESUME_SCHEDULES_ON_START=1`.
48
51
 
49
52
  ### Screenshots
50
53
 
@@ -284,6 +287,10 @@ gemini mcp add the-android-mcp npx the-android-mcp
284
287
  ### Codex
285
288
  On install, the package auto-adds the server to `~/.codex/config.toml` if the file exists.
286
289
  To skip auto-setup, set `THE_ANDROID_MCP_NO_CODEX_SETUP=1`.
290
+ To skip Web UI auto-start on install, set `THE_ANDROID_MCP_NO_WEB_UI_AUTOSTART=1`.
291
+
292
+ Web UI schedule auto-resume on startup is disabled by default to prevent unintended background device actions.
293
+ To explicitly restore active schedules on startup, set `THE_ANDROID_MCP_RESUME_SCHEDULES_ON_START=1`.
287
294
 
288
295
  If you need to add it manually, use:
289
296
  ```toml
@@ -1 +1 @@
1
- {"version":3,"file":"web-ui.d.ts","sourceRoot":"","sources":["../src/web-ui.ts"],"names":[],"mappings":";AAKA,OAAO,IAAyC,MAAM,MAAM,CAAC;AAgB7D,eAAO,MAAM,mBAAmB,cAAc,CAAC;AAC/C,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AA4zczC,wBAAgB,gBAAgB,CAAC,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,IAAI,CAAC,MAAM,CAgC5F;AAED,wBAAsB,qBAAqB,CAAC,OAAO,GAAE;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACV,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBhF"}
1
+ {"version":3,"file":"web-ui.d.ts","sourceRoot":"","sources":["../src/web-ui.ts"],"names":[],"mappings":";AAKA,OAAO,IAAyC,MAAM,MAAM,CAAC;AAgB7D,eAAO,MAAM,mBAAmB,cAAc,CAAC;AAC/C,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAkidzC,wBAAgB,gBAAgB,CAAC,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,IAAI,CAAC,MAAM,CAgC5F;AAED,wBAAsB,qBAAqB,CAAC,OAAO,GAAE;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACV,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBhF"}
package/dist/web-ui.js CHANGED
@@ -41,6 +41,7 @@ const OPS_MISSION_POLICY_FILE = path_1.default.join(APP_STATE_DIR, 'web-ui-ops-m
41
41
  const OPS_MISSION_RUNS_FILE = path_1.default.join(APP_STATE_DIR, 'web-ui-ops-mission-runs.json');
42
42
  const OPS_MISSION_COMMAND_AUDIT_FILE = path_1.default.join(APP_STATE_DIR, 'web-ui-ops-mission-command-audit.json');
43
43
  const OPS_MISSION_COMMAND_SNAPSHOTS_FILE = path_1.default.join(APP_STATE_DIR, 'web-ui-ops-mission-command-snapshots.json');
44
+ const RESUME_SCHEDULES_ON_START_ENV = 'THE_ANDROID_MCP_RESUME_SCHEDULES_ON_START';
44
45
  const SNAPSHOT_KINDS = [
45
46
  'radio',
46
47
  'display',
@@ -120,6 +121,14 @@ function ensureAppStateDir() {
120
121
  fs_1.default.mkdirSync(APP_STATE_DIR, { recursive: true });
121
122
  }
122
123
  }
124
+ function shouldResumeSchedulesOnStart() {
125
+ const raw = process.env[RESUME_SCHEDULES_ON_START_ENV];
126
+ if (!raw) {
127
+ return false;
128
+ }
129
+ const normalized = raw.trim().toLowerCase();
130
+ return normalized === '1' || normalized === 'true' || normalized === 'yes' || normalized === 'on';
131
+ }
123
132
  function appendSessionEvent(event) {
124
133
  try {
125
134
  ensureAppStateDir();
@@ -2967,11 +2976,28 @@ function ensureSchedulesInitialized() {
2967
2976
  return;
2968
2977
  }
2969
2978
  loadSchedules();
2979
+ const resumeOnStart = shouldResumeSchedulesOnStart();
2980
+ let deactivated = 0;
2970
2981
  for (const task of Object.values(schedules)) {
2971
2982
  if (task.active) {
2972
- startSchedule(task.id);
2983
+ if (resumeOnStart) {
2984
+ startSchedule(task.id);
2985
+ }
2986
+ else {
2987
+ task.active = false;
2988
+ task.updatedAt = nowIso();
2989
+ deactivated += 1;
2990
+ }
2973
2991
  }
2974
2992
  }
2993
+ if (!resumeOnStart && deactivated > 0) {
2994
+ saveSchedules();
2995
+ pushEvent('schedule-autoresume-skipped', 'Schedule auto-resume skipped on startup', {
2996
+ deactivated,
2997
+ env: RESUME_SCHEDULES_ON_START_ENV,
2998
+ });
2999
+ console.warn(`[web-ui] schedule auto-resume disabled; deactivated ${deactivated} schedule(s). Set ${RESUME_SCHEDULES_ON_START_ENV}=1 to re-enable.`);
3000
+ }
2975
3001
  schedulesInitialized = true;
2976
3002
  }
2977
3003
  function recorderSessionsList() {
@@ -5386,11 +5412,28 @@ function ensureOpsMissionSchedulesInitialized() {
5386
5412
  return;
5387
5413
  }
5388
5414
  loadOpsMissionSchedules();
5415
+ const resumeOnStart = shouldResumeSchedulesOnStart();
5416
+ let deactivated = 0;
5389
5417
  for (const schedule of Object.values(opsMissionSchedules)) {
5390
5418
  if (schedule.active) {
5391
- startOpsMissionSchedule(schedule.id);
5419
+ if (resumeOnStart) {
5420
+ startOpsMissionSchedule(schedule.id);
5421
+ }
5422
+ else {
5423
+ schedule.active = false;
5424
+ schedule.updatedAt = nowIso();
5425
+ deactivated += 1;
5426
+ }
5392
5427
  }
5393
5428
  }
5429
+ if (!resumeOnStart && deactivated > 0) {
5430
+ saveOpsMissionSchedules();
5431
+ pushEvent('ops-mission-schedule-autoresume-skipped', 'Ops mission schedule auto-resume skipped on startup', {
5432
+ deactivated,
5433
+ env: RESUME_SCHEDULES_ON_START_ENV,
5434
+ });
5435
+ console.warn(`[web-ui] ops mission schedule auto-resume disabled; deactivated ${deactivated} schedule(s). Set ${RESUME_SCHEDULES_ON_START_ENV}=1 to re-enable.`);
5436
+ }
5394
5437
  opsMissionSchedulesInitialized = true;
5395
5438
  }
5396
5439
  function createOpsMissionSchedule(body) {
@@ -8934,21 +8977,21 @@ const INDEX_HTML = String.raw `<!doctype html>
8934
8977
  <link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
8935
8978
  <style>
8936
8979
  :root {
8937
- --bg0: #071019;
8938
- --bg1: #0e1f2d;
8939
- --bg2: #153448;
8940
- --card: #0f1f2cbd;
8941
- --card-strong: #102434f2;
8942
- --line: #2f516bba;
8943
- --line-soft: #3a617d66;
8944
- --text: #eef8ff;
8945
- --muted: #9fbed2;
8946
- --ok: #8eeecf;
8947
- --err: #ff8f9c;
8948
- --acc0: #00d2a6;
8949
- --acc1: #16a8ff;
8950
- --acc2: #75e2ff;
8951
- --warn: #ffc067;
8980
+ --bg0: #0a151f;
8981
+ --bg1: #102334;
8982
+ --bg2: #183a53;
8983
+ --card: #122436e6;
8984
+ --card-strong: #152c41f2;
8985
+ --line: #3f6076b8;
8986
+ --line-soft: #4b71895c;
8987
+ --text: #edf7ff;
8988
+ --muted: #a9c5d8;
8989
+ --ok: #86f2ca;
8990
+ --err: #ff9cab;
8991
+ --acc0: #02c9a4;
8992
+ --acc1: #1ea7ff;
8993
+ --acc2: #8be8ff;
8994
+ --warn: #ffc06f;
8952
8995
  }
8953
8996
  * { box-sizing: border-box; }
8954
8997
  body {
@@ -8957,21 +9000,19 @@ const INDEX_HTML = String.raw `<!doctype html>
8957
9000
  color: var(--text);
8958
9001
  min-height: 100vh;
8959
9002
  background:
8960
- linear-gradient(135deg, #05111cfa, #0a1825e8 45%, #0d2334de),
8961
- url('https://images.unsplash.com/photo-1518770660439-4636190af475?auto=format&fit=crop&w=2200&q=80') center/cover fixed no-repeat;
9003
+ radial-gradient(circle at 10% 10%, #1c3f5f8a 0%, #0a1724 32%, #07131d 65%, #060f16 100%),
9004
+ linear-gradient(180deg, #0a1622, #061019);
8962
9005
  padding: 16px;
8963
9006
  }
8964
9007
  .app { max-width: 1600px; margin: 0 auto; display: grid; gap: 14px; }
8965
9008
  .hero {
8966
9009
  border: 1px solid var(--line);
8967
9010
  border-radius: 20px;
8968
- background:
8969
- linear-gradient(125deg, #0d2538d8, #10263bd1),
8970
- url('https://images.unsplash.com/photo-1498050108023-c5249f4df085?auto=format&fit=crop&w=1800&q=80') center/cover;
9011
+ background: linear-gradient(135deg, #11283c, #0d1f2f 42%, #14324a);
8971
9012
  box-shadow: 0 20px 60px #02090f8c;
8972
- padding: 16px;
9013
+ padding: 18px;
8973
9014
  display: grid;
8974
- gap: 8px;
9015
+ gap: 10px;
8975
9016
  }
8976
9017
  .hero h1 { margin: 0; font-size: 1.55rem; letter-spacing: 0.01em; }
8977
9018
  .hero-badge {
@@ -9009,7 +9050,7 @@ const INDEX_HTML = String.raw `<!doctype html>
9009
9050
  .easy-mode {
9010
9051
  border: 1px solid var(--line);
9011
9052
  border-radius: 20px;
9012
- background: linear-gradient(145deg, #0f2436db, #102638e6);
9053
+ background: linear-gradient(150deg, #11263aef, #11293fef 45%, #142f46eb);
9013
9054
  backdrop-filter: blur(7px);
9014
9055
  padding: 14px;
9015
9056
  display: grid;
@@ -9041,11 +9082,7 @@ const INDEX_HTML = String.raw `<!doctype html>
9041
9082
  border: 1px solid var(--line-soft);
9042
9083
  border-radius: 14px;
9043
9084
  padding: 10px;
9044
- background:
9045
- linear-gradient(145deg, #0f2232e8, #0c1d2be8),
9046
- var(--easy-bg, none);
9047
- background-size: cover;
9048
- background-position: center;
9085
+ background: linear-gradient(145deg, #102435f2, #0e1f2ef2);
9049
9086
  display: grid;
9050
9087
  gap: 7px;
9051
9088
  }
@@ -9110,10 +9147,37 @@ const INDEX_HTML = String.raw `<!doctype html>
9110
9147
  min-width: 240px;
9111
9148
  border-radius: 999px;
9112
9149
  }
9150
+ .advanced-head {
9151
+ grid-column: 1 / -1;
9152
+ border: 1px solid var(--line);
9153
+ border-radius: 14px;
9154
+ background: linear-gradient(140deg, #112537eb, #102132ef);
9155
+ padding: 12px;
9156
+ display: grid;
9157
+ gap: 10px;
9158
+ }
9159
+ .advanced-head h2 {
9160
+ margin: 0;
9161
+ font-size: 1.02rem;
9162
+ }
9163
+ .advanced-head p {
9164
+ margin: 0;
9165
+ color: var(--muted);
9166
+ font-size: 12px;
9167
+ }
9168
+ .advanced-head-actions {
9169
+ display: flex;
9170
+ flex-wrap: wrap;
9171
+ gap: 8px;
9172
+ }
9173
+ .advanced-head-actions button {
9174
+ width: auto;
9175
+ min-width: 200px;
9176
+ }
9113
9177
  .grid {
9114
9178
  display: grid;
9115
9179
  gap: 10px;
9116
- grid-template-columns: 1fr 1fr 1fr;
9180
+ grid-template-columns: repeat(2, minmax(0, 1fr));
9117
9181
  }
9118
9182
  .grid.hidden {
9119
9183
  display: none;
@@ -9184,15 +9248,45 @@ const INDEX_HTML = String.raw `<!doctype html>
9184
9248
  .muted { margin: 0; color: var(--muted); font-size: 12px; }
9185
9249
  .ok { color: var(--ok); }
9186
9250
  .err { color: var(--err); }
9251
+ .ops-group {
9252
+ border: 1px solid var(--line-soft);
9253
+ border-radius: 12px;
9254
+ background: #0d1d2be8;
9255
+ overflow: hidden;
9256
+ }
9257
+ .ops-group + .ops-group {
9258
+ margin-top: 8px;
9259
+ }
9260
+ .ops-group > summary {
9261
+ list-style: none;
9262
+ cursor: pointer;
9263
+ padding: 10px 12px;
9264
+ font-size: 12px;
9265
+ font-weight: 700;
9266
+ letter-spacing: 0.01em;
9267
+ background: linear-gradient(140deg, #122a3e, #102435);
9268
+ }
9269
+ .ops-group > summary::-webkit-details-marker {
9270
+ display: none;
9271
+ }
9272
+ .ops-group[open] > summary {
9273
+ border-bottom: 1px solid var(--line-soft);
9274
+ }
9275
+ .ops-group-body {
9276
+ display: grid;
9277
+ gap: 8px;
9278
+ padding: 10px;
9279
+ }
9187
9280
  @media (max-width: 1300px) {
9188
9281
  .easy-grid { grid-template-columns: 1fr 1fr; }
9189
9282
  .easy-stats { grid-template-columns: 1fr 1fr; }
9190
9283
  }
9191
- @media (max-width: 1200px) { .grid { grid-template-columns: 1fr 1fr; } }
9284
+ @media (max-width: 1200px) { .grid { grid-template-columns: 1fr; } }
9192
9285
  @media (max-width: 900px) {
9193
9286
  .grid { grid-template-columns: 1fr; }
9194
9287
  .easy-grid { grid-template-columns: 1fr; }
9195
9288
  .easy-ops { grid-template-columns: 1fr; }
9289
+ .advanced-head-actions button { width: 100%; min-width: 0; }
9196
9290
  }
9197
9291
  </style>
9198
9292
  </head>
@@ -9208,58 +9302,67 @@ const INDEX_HTML = String.raw `<!doctype html>
9208
9302
  <span class="pill" id="queue-pill">queue: 0</span>
9209
9303
  <span class="pill">port: 50000</span>
9210
9304
  </div>
9211
- <span class="hero-badge">Futuristic Easy Control</span>
9212
- <h1>the-android-mcp v${package_json_1.default.version} command center</h1>
9213
- <p class="muted">Eine Oberfläche für alle: erst einfache Knöpfe, dann bei Bedarf Profi-Tools.</p>
9305
+ <span class="hero-badge">Clear Control Mode</span>
9306
+ <h1>the-android-mcp v${package_json_1.default.version} Control Room</h1>
9307
+ <p class="muted">Start in simple mode. Expert tools are available below in structured, collapsible modules.</p>
9214
9308
  </section>
9215
9309
 
9216
9310
  <section class="easy-mode">
9217
9311
  <div class="easy-head">
9218
- <h2>Easy Mode: 1-Klick Steuerung</h2>
9219
- <p class="easy-note">Für Nicht-Techniker: URL eintragen, großen Knopf drücken, fertig.</p>
9312
+ <h2>Simple Mode: Quick Actions</h2>
9313
+ <p class="easy-note">For everyday use and quick checks: enter a URL, run an action, and read the status.</p>
9220
9314
  </div>
9221
9315
  <div class="easy-grid">
9222
- <article class="easy-card" style="--easy-bg:url('https://images.unsplash.com/photo-1512941937669-90a1b58e7e9c?auto=format&fit=crop&w=1400&q=80')">
9223
- <h3>Schritt 1: Website aufs Handy schicken</h3>
9316
+ <article class="easy-card">
9317
+ <h3>1. Open a website on your device</h3>
9224
9318
  <input id="easy-url-input" type="url" value="https://www.wikipedia.org" />
9225
9319
  <div class="easy-ops">
9226
- <button class="easy-btn" id="easy-open-btn">Website öffnen</button>
9227
- <button class="easy-btn alt" id="easy-smoke-btn">Schnellcheck starten</button>
9320
+ <button class="easy-btn" id="easy-open-btn">Open Website</button>
9321
+ <button class="easy-btn alt" id="easy-smoke-btn">Run Quick Check</button>
9228
9322
  </div>
9229
- <div class="easy-hint" id="easy-last-action">Noch keine Aktion ausgeführt.</div>
9323
+ <div class="easy-hint" id="easy-last-action">No action executed yet.</div>
9230
9324
  </article>
9231
- <article class="easy-card" style="--easy-bg:url('https://images.unsplash.com/photo-1451187580459-43490279c0fa?auto=format&fit=crop&w=1400&q=80')">
9232
- <h3>Schritt 2: Automatisch reparieren</h3>
9325
+ <article class="easy-card">
9326
+ <h3>2. Stabilize and recover</h3>
9233
9327
  <div class="easy-ops">
9234
- <button class="easy-btn alt" id="easy-autofix-btn">Auto-Fix ausführen</button>
9235
- <button class="easy-btn" id="easy-strategy-btn">Turbo-Strategie</button>
9328
+ <button class="easy-btn alt" id="easy-autofix-btn">Run Auto-Fix</button>
9329
+ <button class="easy-btn" id="easy-strategy-btn">Run Turbo Strategy</button>
9236
9330
  </div>
9237
- <button class="easy-btn warn" id="easy-panic-btn">Notfall-Stabilisierung</button>
9331
+ <button class="easy-btn warn" id="easy-panic-btn">Emergency Stabilization</button>
9238
9332
  </article>
9239
9333
  <article class="easy-card">
9240
- <h3>Status in Klartext</h3>
9334
+ <h3>Status Summary</h3>
9241
9335
  <div class="easy-stats">
9242
- <div class="easy-stat"><strong id="easy-risk">-</strong><span>Risiko</span></div>
9243
- <div class="easy-stat"><strong id="easy-mode">-</strong><span>Modus</span></div>
9244
- <div class="easy-stat"><strong id="easy-device">-</strong><span>Geräte</span></div>
9336
+ <div class="easy-stat"><strong id="easy-risk">-</strong><span>Risk</span></div>
9337
+ <div class="easy-stat"><strong id="easy-mode">-</strong><span>Mode</span></div>
9338
+ <div class="easy-stat"><strong id="easy-device">-</strong><span>Devices</span></div>
9245
9339
  <div class="easy-stat"><strong id="easy-jobs">-</strong><span>Jobs</span></div>
9246
9340
  </div>
9247
- <div class="easy-hint" id="easy-recommendation">Empfehlung wird geladen ...</div>
9341
+ <div class="easy-hint" id="easy-recommendation">Loading recommendation ...</div>
9248
9342
  </article>
9249
9343
  </div>
9250
9344
  <div class="advanced-toggle-wrap">
9251
- <button class="s advanced-toggle-btn" id="easy-toggle-advanced-btn">Profi-Bereich einblenden</button>
9345
+ <button class="s advanced-toggle-btn" id="easy-toggle-advanced-btn">Show Expert Area</button>
9252
9346
  </div>
9253
9347
  </section>
9254
9348
 
9255
9349
  <section class="grid hidden" id="advanced-grid">
9350
+ <div class="advanced-head">
9351
+ <h2>Expert Area</h2>
9352
+ <p>All features remain available. Larger tool collections are grouped into thematic, collapsible modules.</p>
9353
+ <div class="advanced-head-actions">
9354
+ <button class="s" id="advanced-expand-all-btn">Expand All Modules</button>
9355
+ <button class="s" id="advanced-collapse-all-btn">Collapse All Modules</button>
9356
+ </div>
9357
+ </div>
9256
9358
  <article class="card stack">
9257
- <h2>Device operations</h2>
9359
+ <h2>Direct Device Control</h2>
9360
+ <p class="muted">Run direct actions on the currently connected device.</p>
9258
9361
  <select id="device-select"></select>
9259
9362
  <input id="url-input" type="url" value="https://www.wikipedia.org" />
9260
9363
  <div class="split">
9261
9364
  <button class="p" id="open-url-btn">Open URL</button>
9262
- <button class="p" id="suite-btn">Run suite</button>
9365
+ <button class="p" id="suite-btn">Run Diagnostic Suite</button>
9263
9366
  </div>
9264
9367
  <div class="quick">
9265
9368
  <button class="s quick-url" data-url="https://www.wikipedia.org">Wikipedia</button>
@@ -9268,14 +9371,15 @@ const INDEX_HTML = String.raw `<!doctype html>
9268
9371
  <button class="s quick-url" data-url="https://www.youtube.com">YouTube</button>
9269
9372
  </div>
9270
9373
  <div class="split">
9271
- <button class="s" id="profile-btn">Device profile</button>
9272
- <button class="s" id="profiles-btn">Profiles all</button>
9374
+ <button class="s" id="profile-btn">Load Device Profile</button>
9375
+ <button class="s" id="profiles-btn">Profiles for All Devices</button>
9273
9376
  </div>
9274
9377
  <p class="muted">Update hint: <code>npm install -g the-android-mcp@latest</code></p>
9275
9378
  </article>
9276
9379
 
9277
9380
  <article class="card stack">
9278
- <h2>Snapshot + stress</h2>
9381
+ <h2>Diagnostics & Stress Testing</h2>
9382
+ <p class="muted">Capture snapshots, compare deltas, and run URL loop tests.</p>
9279
9383
  <select id="snapshot-kind">
9280
9384
  <option value="radio">radio</option>
9281
9385
  <option value="display">display</option>
@@ -9298,7 +9402,8 @@ https://developer.android.com</textarea>
9298
9402
  </article>
9299
9403
 
9300
9404
  <article class="card stack">
9301
- <h2>Workflow engine</h2>
9405
+ <h2>Manage Workflows</h2>
9406
+ <p class="muted">Save, run, and export multi-step flows.</p>
9302
9407
  <select id="workflow-select"></select>
9303
9408
  <input id="workflow-name" placeholder="workflow name" />
9304
9409
  <textarea id="workflow-steps">[
@@ -9318,7 +9423,8 @@ https://developer.android.com</textarea>
9318
9423
  </article>
9319
9424
 
9320
9425
  <article class="card stack">
9321
- <h2>Job orchestrator</h2>
9426
+ <h2>Jobs & Queue</h2>
9427
+ <p class="muted">Queue single jobs or batch jobs.</p>
9322
9428
  <select id="job-type">
9323
9429
  <option value="open_url">open_url</option>
9324
9430
  <option value="snapshot_suite">snapshot_suite</option>
@@ -9342,13 +9448,15 @@ https://developer.android.com</textarea>
9342
9448
  </article>
9343
9449
 
9344
9450
  <article class="card stack">
9345
- <h2>Lanes + events</h2>
9451
+ <h2>Live Status & Events</h2>
9452
+ <p class="muted">Current lanes and event feed in realtime.</p>
9346
9453
  <div id="lanes" class="lanes"></div>
9347
9454
  <div id="events" class="events"></div>
9348
9455
  </article>
9349
9456
 
9350
9457
  <article class="card stack">
9351
- <h2>Queue control + autopilot</h2>
9458
+ <h2>Advanced Control</h2>
9459
+ <p class="muted">Autopilot, policies, schedules, and missions grouped into modules.</p>
9352
9460
  <div class="split">
9353
9461
  <button class="w" id="pause-all-lanes-btn">Pause all lanes</button>
9354
9462
  <button class="p" id="resume-all-lanes-btn">Resume all lanes</button>
@@ -9747,7 +9855,7 @@ https://developer.android.com</textarea>
9747
9855
  </article>
9748
9856
 
9749
9857
  <article class="card stack">
9750
- <h2>Metrics + session</h2>
9858
+ <h2>Metriken & Sitzung</h2>
9751
9859
  <div id="metrics" class="metrics"></div>
9752
9860
  <div class="split">
9753
9861
  <button class="s" id="refresh-state-btn">Refresh state</button>
@@ -9897,6 +10005,8 @@ https://developer.android.com</textarea>
9897
10005
  const $easyLastAction = document.getElementById('easy-last-action');
9898
10006
  const $advancedGrid = document.getElementById('advanced-grid');
9899
10007
  const $easyToggleAdvancedBtn = document.getElementById('easy-toggle-advanced-btn');
10008
+ const $advancedExpandAllBtn = document.getElementById('advanced-expand-all-btn');
10009
+ const $advancedCollapseAllBtn = document.getElementById('advanced-collapse-all-btn');
9900
10010
 
9901
10011
  function setMessage(text, isError) {
9902
10012
  $message.textContent = text;
@@ -10766,46 +10876,152 @@ https://developer.android.com</textarea>
10766
10876
  async function easyOpenWebsiteUi() {
10767
10877
  const url = ($easyUrlInput && $easyUrlInput.value ? $easyUrlInput.value : $urlInput.value || '').trim();
10768
10878
  if (!url) {
10769
- throw new Error('Bitte eine URL eintragen.');
10879
+ throw new Error('Please enter a URL.');
10770
10880
  }
10771
10881
  $urlInput.value = url;
10772
10882
  await openUrl(url);
10773
- setEasyLastAction('Website geöffnet: ' + url, false);
10883
+ setEasyLastAction('Website opened: ' + url, false);
10774
10884
  await loadEasyOverview();
10775
10885
  }
10776
10886
 
10777
10887
  async function easySmokeUi() {
10778
10888
  await runDeviceSmoke();
10779
10889
  await runSuite();
10780
- setEasyLastAction('Schnellcheck abgeschlossen.', false);
10890
+ setEasyLastAction('Quick check completed.', false);
10781
10891
  await loadEasyOverview();
10782
10892
  }
10783
10893
 
10784
10894
  async function easyAutoFixUi() {
10785
10895
  await runOpsMissionCommandQuickFixUi();
10786
- setEasyLastAction('Auto-Fix wurde ausgeführt.', false);
10896
+ setEasyLastAction('Auto-fix executed.', false);
10787
10897
  await loadEasyOverview();
10788
10898
  }
10789
10899
 
10790
10900
  async function easyStrategyUi() {
10791
10901
  await executeOpsMissionCommandStrategyUi();
10792
- setEasyLastAction('Turbo-Strategie abgeschlossen.', false);
10902
+ setEasyLastAction('Turbo strategy completed.', false);
10793
10903
  await loadEasyOverview();
10794
10904
  }
10795
10905
 
10796
10906
  async function easyPanicUi() {
10797
10907
  await runOpsStabilizeUi();
10798
10908
  await runWatchdogUi();
10799
- setEasyLastAction('Notfall-Stabilisierung abgeschlossen.', false);
10909
+ setEasyLastAction('Emergency stabilization completed.', false);
10800
10910
  await loadEasyOverview();
10801
10911
  }
10802
10912
 
10913
+ let advancedUiStructured = false;
10914
+
10915
+ function structureAdvancedUi() {
10916
+ if (advancedUiStructured || !$advancedGrid) {
10917
+ return;
10918
+ }
10919
+
10920
+ const cards = Array.from($advancedGrid.querySelectorAll('article.card.stack'));
10921
+ const opsCard = cards.find(function (card) {
10922
+ const title = card.querySelector('h2');
10923
+ const text = title && title.textContent ? title.textContent.trim().toLowerCase() : '';
10924
+ return text.includes('erweiterte steuerung') || text.includes('queue control');
10925
+ });
10926
+
10927
+ if (!opsCard) {
10928
+ advancedUiStructured = true;
10929
+ return;
10930
+ }
10931
+
10932
+ const titleNode = opsCard.querySelector('h2');
10933
+ if (!titleNode) {
10934
+ advancedUiStructured = true;
10935
+ return;
10936
+ }
10937
+
10938
+ const allChildren = Array.from(opsCard.children);
10939
+ const contentNodes = allChildren.filter(function (node) {
10940
+ return node !== titleNode && !(node instanceof HTMLElement && node.tagName.toLowerCase() === 'p' && node.classList.contains('muted'));
10941
+ });
10942
+
10943
+ const groups = [];
10944
+ let current = [];
10945
+ for (const node of contentNodes) {
10946
+ if (node instanceof HTMLElement && node.tagName.toLowerCase() === 'hr') {
10947
+ if (current.length > 0) {
10948
+ groups.push(current);
10949
+ current = [];
10950
+ }
10951
+ continue;
10952
+ }
10953
+ current.push(node);
10954
+ }
10955
+ if (current.length > 0) {
10956
+ groups.push(current);
10957
+ }
10958
+
10959
+ const labels = [
10960
+ 'Immediate Actions: Queue, Smoke, Autopilot',
10961
+ 'Recorder: Capture & Replay',
10962
+ 'Presets & Heatmap',
10963
+ 'Policy, Runbook & Transactions',
10964
+ 'Queue Board & Schedules',
10965
+ 'Alert Rules',
10966
+ 'Import/Export, Baselines, Campaigns',
10967
+ 'Stabilization & Control Room',
10968
+ 'Policy Presets',
10969
+ 'Watchdog Profiles',
10970
+ 'Ops Action Queue',
10971
+ 'Gate Checks',
10972
+ 'Missions',
10973
+ 'Mission Schedules & Analytics',
10974
+ 'Mission Policy',
10975
+ 'Additional Tools',
10976
+ ];
10977
+
10978
+ for (const node of contentNodes) {
10979
+ if (node.parentNode === opsCard) {
10980
+ opsCard.removeChild(node);
10981
+ }
10982
+ }
10983
+
10984
+ for (let index = 0; index < groups.length; index += 1) {
10985
+ const details = document.createElement('details');
10986
+ details.className = 'ops-group';
10987
+ details.open = index < 2;
10988
+
10989
+ const summary = document.createElement('summary');
10990
+ summary.textContent = labels[index] || ('Module ' + String(index + 1));
10991
+ details.appendChild(summary);
10992
+
10993
+ const body = document.createElement('div');
10994
+ body.className = 'ops-group-body';
10995
+ for (const node of groups[index]) {
10996
+ body.appendChild(node);
10997
+ }
10998
+
10999
+ details.appendChild(body);
11000
+ opsCard.appendChild(details);
11001
+ }
11002
+
11003
+ advancedUiStructured = true;
11004
+ }
11005
+
11006
+ function setOpsGroupsOpen(open) {
11007
+ if (!$advancedGrid) {
11008
+ return;
11009
+ }
11010
+ const groups = $advancedGrid.querySelectorAll('.ops-group');
11011
+ for (const group of groups) {
11012
+ group.open = open;
11013
+ }
11014
+ }
11015
+
10803
11016
  function toggleAdvancedUi() {
10804
11017
  if (!$advancedGrid || !$easyToggleAdvancedBtn) {
10805
11018
  return;
10806
11019
  }
10807
11020
  const hidden = $advancedGrid.classList.toggle('hidden');
10808
- $easyToggleAdvancedBtn.textContent = hidden ? 'Profi-Bereich einblenden' : 'Profi-Bereich ausblenden';
11021
+ if (!hidden) {
11022
+ structureAdvancedUi();
11023
+ }
11024
+ $easyToggleAdvancedBtn.textContent = hidden ? 'Show Expert Area' : 'Hide Expert Area';
10809
11025
  }
10810
11026
 
10811
11027
  function connectRealtime() {
@@ -10865,7 +11081,7 @@ https://developer.android.com</textarea>
10865
11081
  if ($easyUrlInput) {
10866
11082
  $easyUrlInput.value = url;
10867
11083
  }
10868
- setEasyLastAction('Website geöffnet: ' + url, false);
11084
+ setEasyLastAction('Website opened: ' + url, false);
10869
11085
  setMessage('URL opened', false);
10870
11086
  }
10871
11087
 
@@ -13062,6 +13278,20 @@ https://developer.android.com</textarea>
13062
13278
  toggleAdvancedUi();
13063
13279
  });
13064
13280
  }
13281
+ if ($advancedExpandAllBtn) {
13282
+ $advancedExpandAllBtn.addEventListener('click', function () {
13283
+ structureAdvancedUi();
13284
+ setOpsGroupsOpen(true);
13285
+ setMessage('Expanded all expert modules', false);
13286
+ });
13287
+ }
13288
+ if ($advancedCollapseAllBtn) {
13289
+ $advancedCollapseAllBtn.addEventListener('click', function () {
13290
+ structureAdvancedUi();
13291
+ setOpsGroupsOpen(false);
13292
+ setMessage('Collapsed all expert modules', false);
13293
+ });
13294
+ }
13065
13295
 
13066
13296
  document.getElementById('open-url-btn').addEventListener('click', async function () {
13067
13297
  try { await openUrl($urlInput.value); } catch (error) { setMessage(String(error), true); }
@@ -13494,13 +13724,14 @@ https://developer.android.com</textarea>
13494
13724
 
13495
13725
  async function init() {
13496
13726
  try {
13727
+ structureAdvancedUi();
13497
13728
  ensureOpsMissionCommandCenterUi();
13498
13729
  await refreshCore();
13499
13730
  if ($easyUrlInput && !$easyUrlInput.value) {
13500
13731
  $easyUrlInput.value = $urlInput.value || 'https://www.wikipedia.org';
13501
13732
  }
13502
13733
  await loadEasyOverview();
13503
- setEasyLastAction('Bereit. Wähle eine Aktion oben im Easy Mode.', false);
13734
+ setEasyLastAction('Ready. Choose an action in Simple Mode above.', false);
13504
13735
  const history = await api('/api/history?limit=45');
13505
13736
  const events = Array.isArray(history.events) ? history.events : [];
13506
13737
  for (let i = events.length - 1; i >= 0; i -= 1) {