diff --git a/frontend/index.html b/frontend/index.html
index 3a7a223..61a6480 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -1277,14 +1277,33 @@ function cmdRows(cmd) {
const kids = apdu.children || [];
const insKid = kids.find(k => k.label === 'INS');
const name = insKid ? (insKid.desc || '') : apdu.label;
- rows.push(['C-APDU #' + n + ' — ' + (name || apdu.label),
- apdu.hex || '' + (apdu.label === 'APDU (implied CLA)' ? ' (implied CLA)' : '')]);
+ rows.push(['C-APDU #' + n + ' — ' + (name || apdu.label) +
+ (apdu.label.includes('implied CLA') ? ' (implied CLA)' : ''),
+ apdu.hex || '']);
+ // Compact layout: pair CLA+INS and P1+P2; skip a
+ // desc that merely repeats the hex value.
+ const fmtKid = k => {
+ let v = k.hex || '';
+ if (k.desc && k.desc !== k.hex) v += ' — ' + k.desc;
+ return v;
+ };
+ const byLabel = {};
+ for (const k of kids) byLabel[k.label] = k;
+ const pairs = [['CLA', 'INS'], ['P1', 'P2']];
+ const done = new Set();
+ for (const [a, b] of pairs) {
+ if (byLabel[a] && byLabel[b]) {
+ rows.push(['· ' + a + ', ' + b,
+ fmtKid(byLabel[a]) + ', ' + fmtKid(byLabel[b])]);
+ done.add(a);
+ done.add(b);
+ }
+ }
for (const k of kids) {
- rows.push(['· ' + k.label,
- (k.hex || '') + (k.desc ? ' — ' + k.desc : '')]);
+ if (done.has(k.label)) continue;
+ rows.push(['· ' + k.label, fmtKid(k)]);
if (k.children) for (const c of k.children) {
- rows.push(['· · ' + c.label,
- (c.hex || '') + (c.desc ? ' — ' + c.desc : '')]);
+ rows.push(['· · ' + c.label, fmtKid(c)]);
}
}
}
@@ -2465,7 +2484,7 @@ function onFilterChange() {
}
// ──────────────────── Versioning ────────────────────
-const PWA_VERSION = '1.20.1';
+const PWA_VERSION = '1.20.2';
const MIN_SERVER_VERSION = '1.0.0';
function parseVersion(v) {
diff --git a/frontend/sw.js b/frontend/sw.js
index a11734f..d8ce4b6 100644
--- a/frontend/sw.js
+++ b/frontend/sw.js
@@ -1,4 +1,4 @@
-const CACHE = 'simtrace-analyser-v29';
+const CACHE = 'simtrace-analyser-v30';
const PRECACHE = [
'index.html',
diff --git a/pyproject.toml b/pyproject.toml
index 02a2500..61bf353 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend"
[project]
name = "simtrace2-pysniff"
-version = "1.20.1"
+version = "1.20.2"
description = "Python-based sniffing tool for SIMtrace2 hardware (SIM card communication sniffer)"
readme = {file = "README.md", content-type = "text/markdown"}
license = {text = "GPL-2.0-or-later"}
diff --git a/simtrace2_pysniff/__init__.py b/simtrace2_pysniff/__init__.py
index 61651b8..bbcf1ce 100644
--- a/simtrace2_pysniff/__init__.py
+++ b/simtrace2_pysniff/__init__.py
@@ -6,7 +6,7 @@ from .gsmtap import GsmtapSender, GsmtapReceiver
from .pcap import PcapWriter
from .dump import FileDumper, format_message
-__version__ = '1.20.1'
+__version__ = '1.20.2'
__all__ = [
'SniffSession',
'DeviceDisconnected',
diff --git a/tests/test_pcap_import.py b/tests/test_pcap_import.py
index 7e5dada..db050f4 100644
--- a/tests/test_pcap_import.py
+++ b/tests/test_pcap_import.py
@@ -197,7 +197,7 @@ class TestImportEndpoint(unittest.TestCase):
class TestVersion(unittest.TestCase):
def test_package_version(self):
from simtrace2_pysniff import __version__
- self.assertEqual(__version__, '1.20.1')
+ self.assertEqual(__version__, '1.20.2')
def test_status_includes_version(self):
import os