feat(mobile): show SSH host health on the workspace row badge (#26415)

* feat(mobile): show SSH host health on the workspace row host badge

Rows on an SSH host the desktop cannot reach looked healthy on the phone. The badge now
adds the desktop sidebar's own word ("devbox · Disconnected"), derived by the same shared
function from the connection status ssh.listTargetSummaries already sends; old desktops keep today's badge.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* feat(mobile): name an unhealthy SSH host even in a single-host list

The desktop card shows SSH status on any host count, so the phone now reads target summaries
whenever a repo is on SSH and badges an unhealthy host alone too. Labels and health share one
target-to-host keying, and a hook-level test pins the reply-to-row wiring.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): clear stale SSH host badges and announce them without the dot

A catalog that no longer spans hosts or holds an SSH repo now clears the health and label maps,
so a host that left cannot keep badging rows. The badge gets a screen-reader label ("devbox,
Disconnected") instead of reading the middle dot.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* test(mobile): type the single-host health fixtures inline so the test tsc passes

Fixtures hoisted into consts widened their health maps to string, which the now-required
hostHealthById rejects under the tests-typecheck ratchet; passing them inline keeps the union.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* test(mobile): re-record the repo-metadata goldens for SSH host health

The settled metadata state now carries hostHealthById, and an SSH-only catalog now reads the
target summaries so a lone unhealthy host can be badged. Scoped re-record via rpc-recording.mts.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
This commit is contained in:
Jinwoo Hong
2026-10-11 02:53:57 -04:00
committed by GitHub
parent 58d1d8d101
commit 7abee44e78
37 changed files with 1699 additions and 926 deletions
@@ -38,23 +38,6 @@
}
}
},
"071880b671a1": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"0c4296f215a4": {
"name": "settings.get#1",
"ordinal": 8,
@@ -195,25 +178,6 @@
"startedAt": 0
}
},
"1de50f3b4aac": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": {
"$rpc": "null"
},
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"1ff13ee8621c": {
"name": "repoIconsByName",
"ordinal": 4,
@@ -417,6 +381,11 @@
}
}
},
"53226cb82ec3": {
"name": "hostPlatform",
"ordinal": 15,
"value": "linux"
},
"53dea128b181": {
"name": "host.platform#1",
"ordinal": 9,
@@ -484,10 +453,10 @@
}
}
},
"56ab81cb67dc": {
"name": "hostLabelById",
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": [["ssh:ssh-1", "SSH"]]
"value": []
},
"6134b73f18d0": {
"repoColorsByName": [
@@ -618,11 +587,23 @@
}
}
},
"9d20695fdb34": {
"name": "hostPlatform",
"ordinal": 15,
"value": {
"$rpc": "null"
}
},
"b428bce85ee7": {
"name": "settings.get#1",
"ordinal": 11,
"json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"bea13a4a2e87": {
"name": "hostLabelById",
"ordinal": 14,
"value": [["ssh:ssh-1", "SSH"]]
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
@@ -697,12 +678,25 @@
}
}
},
"e9480602a4c6": {
"name": "hostPlatform",
"ordinal": 14,
"value": {
"e841f87c65aa": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": {
"$rpc": "null"
}
},
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"eb79a9b3682a": {
"status": "fulfilled",
@@ -712,10 +706,23 @@
"$rpc": "undefined"
}
},
"f9193cae5824": {
"name": "hostPlatform",
"ordinal": 14,
"value": "linux"
"f4667dda0187": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
}
},
"recording": {
@@ -749,8 +756,9 @@
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -763,14 +771,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -783,14 +792,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -803,14 +813,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -823,14 +834,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -843,14 +855,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -863,14 +876,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -883,14 +897,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -903,14 +918,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -923,14 +939,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -943,14 +960,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -963,14 +981,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
}
@@ -38,23 +38,6 @@
}
}
},
"071880b671a1": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"0c4296f215a4": {
"name": "settings.get#1",
"ordinal": 8,
@@ -327,10 +310,15 @@
}
}
},
"56ab81cb67dc": {
"name": "hostLabelById",
"53226cb82ec3": {
"name": "hostPlatform",
"ordinal": 15,
"value": "linux"
},
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": [["ssh:ssh-1", "SSH"]]
"value": []
},
"6134b73f18d0": {
"repoColorsByName": [
@@ -504,6 +492,11 @@
"ordinal": 11,
"json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"bea13a4a2e87": {
"name": "hostLabelById",
"ordinal": 14,
"value": [["ssh:ssh-1", "SSH"]]
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
@@ -655,10 +648,23 @@
}
}
},
"f9193cae5824": {
"name": "hostPlatform",
"ordinal": 14,
"value": "linux"
"f4667dda0187": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
}
},
"recording": {
@@ -686,14 +692,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -38,23 +38,6 @@
}
}
},
"071880b671a1": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"0c4296f215a4": {
"name": "settings.get#1",
"ordinal": 8,
@@ -295,6 +278,11 @@
}
}
},
"53226cb82ec3": {
"name": "hostPlatform",
"ordinal": 15,
"value": "linux"
},
"53dea128b181": {
"name": "host.platform#1",
"ordinal": 9,
@@ -327,10 +315,10 @@
}
}
},
"56ab81cb67dc": {
"name": "hostLabelById",
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": [["ssh:ssh-1", "SSH"]]
"value": []
},
"6134b73f18d0": {
"repoColorsByName": [
@@ -496,6 +484,13 @@
"startedAt": 0
}
},
"9d20695fdb34": {
"name": "hostPlatform",
"ordinal": 15,
"value": {
"$rpc": "null"
}
},
"ae308dad876a": {
"name": "settings.get#1",
"ordinal": 8,
@@ -567,6 +562,11 @@
}
}
},
"bea13a4a2e87": {
"name": "hostLabelById",
"ordinal": 14,
"value": [["ssh:ssh-1", "SSH"]]
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
@@ -710,13 +710,6 @@
}
}
},
"e9480602a4c6": {
"name": "hostPlatform",
"ordinal": 14,
"value": {
"$rpc": "null"
}
},
"eb79a9b3682a": {
"status": "fulfilled",
"startedAt": 0,
@@ -725,10 +718,23 @@
"$rpc": "undefined"
}
},
"f9193cae5824": {
"name": "hostPlatform",
"ordinal": 14,
"value": "linux"
"f4667dda0187": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
}
},
"recording": {
@@ -762,8 +768,9 @@
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -776,14 +783,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -796,14 +804,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -816,14 +825,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -836,14 +846,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -856,14 +867,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -876,14 +888,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -896,14 +909,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -916,14 +930,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -936,14 +951,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -956,14 +972,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -976,14 +993,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
}
@@ -72,23 +72,6 @@
}
}
},
"071880b671a1": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"08d05f42e4a2": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
@@ -427,13 +410,31 @@
}
}
},
"56ab81cb67dc": {
"name": "hostLabelById",
"ordinal": 13,
"value": [["ssh:ssh-1", "SSH"]]
"523753167e39": {
"hostHealthById": [],
"hostLabelById": [],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"5ffccd000213": {
"name": "hostLabelById",
"53226cb82ec3": {
"name": "hostPlatform",
"ordinal": 15,
"value": "linux"
},
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": []
},
@@ -577,6 +578,11 @@
"ordinal": 11,
"json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"bea13a4a2e87": {
"name": "hostLabelById",
"ordinal": 14,
"value": [["ssh:ssh-1", "SSH"]]
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
@@ -616,8 +622,22 @@
}
}
},
"eb68427ac627": {
"hostLabelById": [],
"daecdc0e521b": {
"name": "hostLabelById",
"ordinal": 14,
"value": []
},
"eb79a9b3682a": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"$rpc": "undefined"
}
},
"f4667dda0187": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
@@ -633,19 +653,6 @@
["Remote", "repo-2"]
]
},
"eb79a9b3682a": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"$rpc": "undefined"
}
},
"f9193cae5824": {
"name": "hostPlatform",
"ordinal": 14,
"value": "linux"
},
"fa2cb04c517b": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
@@ -707,14 +714,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -740,14 +748,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "eb68427ac627",
"state": "523753167e39",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"5ffccd000213",
"f9193cae5824"
"6063e534d9db",
"daecdc0e521b",
"53226cb82ec3"
]
}
},
@@ -773,14 +782,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "eb68427ac627",
"state": "523753167e39",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"5ffccd000213",
"f9193cae5824"
"6063e534d9db",
"daecdc0e521b",
"53226cb82ec3"
]
}
},
@@ -806,14 +816,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "eb68427ac627",
"state": "523753167e39",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"5ffccd000213",
"f9193cae5824"
"6063e534d9db",
"daecdc0e521b",
"53226cb82ec3"
]
}
},
@@ -839,14 +850,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "eb68427ac627",
"state": "523753167e39",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"5ffccd000213",
"f9193cae5824"
"6063e534d9db",
"daecdc0e521b",
"53226cb82ec3"
]
}
},
@@ -872,14 +884,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "eb68427ac627",
"state": "523753167e39",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"5ffccd000213",
"f9193cae5824"
"6063e534d9db",
"daecdc0e521b",
"53226cb82ec3"
]
}
},
@@ -905,14 +918,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "eb68427ac627",
"state": "523753167e39",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"5ffccd000213",
"f9193cae5824"
"6063e534d9db",
"daecdc0e521b",
"53226cb82ec3"
]
}
},
@@ -938,14 +952,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "eb68427ac627",
"state": "523753167e39",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"5ffccd000213",
"f9193cae5824"
"6063e534d9db",
"daecdc0e521b",
"53226cb82ec3"
]
}
},
@@ -971,14 +986,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "eb68427ac627",
"state": "523753167e39",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"5ffccd000213",
"f9193cae5824"
"6063e534d9db",
"daecdc0e521b",
"53226cb82ec3"
]
}
},
@@ -1004,14 +1020,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "eb68427ac627",
"state": "523753167e39",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"5ffccd000213",
"f9193cae5824"
"6063e534d9db",
"daecdc0e521b",
"53226cb82ec3"
]
}
},
@@ -1037,14 +1054,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "eb68427ac627",
"state": "523753167e39",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"5ffccd000213",
"f9193cae5824"
"6063e534d9db",
"daecdc0e521b",
"53226cb82ec3"
]
}
}
@@ -75,23 +75,6 @@
}
}
},
"071880b671a1": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"0c4296f215a4": {
"name": "settings.get#1",
"ordinal": 8,
@@ -163,25 +146,6 @@
"startedAt": 0
}
},
"1de50f3b4aac": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": {
"$rpc": "null"
},
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"1ff13ee8621c": {
"name": "repoIconsByName",
"ordinal": 4,
@@ -279,6 +243,11 @@
}
}
},
"53226cb82ec3": {
"name": "hostPlatform",
"ordinal": 15,
"value": "linux"
},
"53dea128b181": {
"name": "host.platform#1",
"ordinal": 9,
@@ -311,11 +280,6 @@
}
}
},
"56ab81cb67dc": {
"name": "hostLabelById",
"ordinal": 13,
"value": [["ssh:ssh-1", "SSH"]]
},
"5b781918b903": {
"name": "host.platform#1",
"ordinal": 9,
@@ -348,6 +312,11 @@
}
}
},
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": []
},
"6134b73f18d0": {
"repoColorsByName": [
["Local", "#6366f1"],
@@ -515,11 +484,23 @@
}
}
},
"9d20695fdb34": {
"name": "hostPlatform",
"ordinal": 15,
"value": {
"$rpc": "null"
}
},
"b428bce85ee7": {
"name": "settings.get#1",
"ordinal": 11,
"json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"bea13a4a2e87": {
"name": "hostLabelById",
"ordinal": 14,
"value": [["ssh:ssh-1", "SSH"]]
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
@@ -631,12 +612,25 @@
}
}
},
"e9480602a4c6": {
"name": "hostPlatform",
"ordinal": 14,
"value": {
"e841f87c65aa": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": {
"$rpc": "null"
}
},
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"eb79a9b3682a": {
"status": "fulfilled",
@@ -646,10 +640,23 @@
"$rpc": "undefined"
}
},
"f9193cae5824": {
"name": "hostPlatform",
"ordinal": 14,
"value": "linux"
"f4667dda0187": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
}
},
"recording": {
@@ -677,14 +684,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -710,14 +718,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -743,14 +752,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -776,14 +786,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -828,8 +839,9 @@
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -842,14 +854,15 @@
"mount": "eb79a9b3682a",
"load": "c7f150c7a054"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -863,14 +876,15 @@
"load": "eb79a9b3682a",
"disconnect": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
},
@@ -884,14 +898,15 @@
"load": "eb79a9b3682a",
"cutover": "eb79a9b3682a"
},
"state": "1de50f3b4aac",
"state": "e841f87c65aa",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"e9480602a4c6"
"6063e534d9db",
"bea13a4a2e87",
"9d20695fdb34"
]
}
}
@@ -4,32 +4,6 @@
"family": "settings.repo-metadata",
"namedDeltas": [],
"values": {
"00271b9f4a55": {
"name": "repo.list#2",
"ordinal": 15,
"args": [
{
"name": "method",
"value": "repo.list"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "pending",
"startedAt": 60000
}
},
"03c9a2ba60b9": {
"name": "host.platform#1",
"ordinal": 9,
@@ -64,23 +38,6 @@
}
}
},
"071880b671a1": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"0c4296f215a4": {
"name": "settings.get#1",
"ordinal": 8,
@@ -157,6 +114,11 @@
"ordinal": 4,
"value": []
},
"2053629911e7": {
"name": "repo.list#2",
"ordinal": 17,
"json": "{\"id\":\"frame-5\",\"deviceToken\":\"recording-device\",\"method\":\"repo.list\"}"
},
"2f1b95eac8f1": {
"name": "repoColorsByName",
"ordinal": 3,
@@ -217,10 +179,15 @@
}
}
},
"56ab81cb67dc": {
"name": "hostLabelById",
"53226cb82ec3": {
"name": "hostPlatform",
"ordinal": 15,
"value": "linux"
},
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": [["ssh:ssh-1", "SSH"]]
"value": []
},
"6134b73f18d0": {
"repoColorsByName": [
@@ -297,6 +264,37 @@
"status": "pending",
"startedAt": 60000
},
"bea13a4a2e87": {
"name": "hostLabelById",
"ordinal": 14,
"value": [["ssh:ssh-1", "SSH"]]
},
"c402c05b8b96": {
"name": "repo.list#2",
"ordinal": 16,
"args": [
{
"name": "method",
"value": "repo.list"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "pending",
"startedAt": 60000
}
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
@@ -336,11 +334,6 @@
}
}
},
"de81371c7ac8": {
"name": "repo.list#2",
"ordinal": 16,
"json": "{\"id\":\"frame-5\",\"deviceToken\":\"recording-device\",\"method\":\"repo.list\"}"
},
"eb79a9b3682a": {
"status": "fulfilled",
"startedAt": 0,
@@ -357,10 +350,23 @@
"$rpc": "undefined"
}
},
"f9193cae5824": {
"name": "hostPlatform",
"ordinal": 14,
"value": "linux"
"f4667dda0187": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
}
},
"recording": {
@@ -388,14 +394,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -409,14 +416,15 @@
"load": "eb79a9b3682a",
"cached-query": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -431,14 +439,15 @@
"cached-query": "eb79a9b3682a",
"warm-query": "f43afee17848"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -450,14 +459,14 @@
"c752e67787f9",
"0c4296f215a4",
"03c9a2ba60b9",
"00271b9f4a55"
"c402c05b8b96"
],
"payloads": [
"19b2979d7fc2",
"668a7e313975",
"b428bce85ee7",
"36a96ddbd396",
"de81371c7ac8"
"2053629911e7"
],
"settlements": {
"mount": "eb79a9b3682a",
@@ -466,14 +475,15 @@
"warm-query": "f43afee17848",
"expired-query": "ba8a19e3e2b1"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
}
@@ -38,23 +38,6 @@
}
}
},
"071880b671a1": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"0c4296f215a4": {
"name": "settings.get#1",
"ordinal": 8,
@@ -191,10 +174,15 @@
}
}
},
"56ab81cb67dc": {
"name": "hostLabelById",
"53226cb82ec3": {
"name": "hostPlatform",
"ordinal": 15,
"value": "linux"
},
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": [["ssh:ssh-1", "SSH"]]
"value": []
},
"6134b73f18d0": {
"repoColorsByName": [
@@ -267,6 +255,11 @@
"ordinal": 11,
"json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"bea13a4a2e87": {
"name": "hostLabelById",
"ordinal": 14,
"value": [["ssh:ssh-1", "SSH"]]
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
@@ -314,10 +307,23 @@
"$rpc": "undefined"
}
},
"f9193cae5824": {
"name": "hostPlatform",
"ordinal": 14,
"value": "linux"
"f4667dda0187": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
}
},
"recording": {
@@ -345,14 +351,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
}
@@ -4,11 +4,6 @@
"family": "settings.repo-metadata",
"namedDeltas": [],
"values": {
"12ba3f41d4db": {
"name": "hostPlatform",
"ordinal": 14,
"value": "darwin"
},
"19b2979d7fc2": {
"name": "repo.list#1",
"ordinal": 2,
@@ -49,15 +44,20 @@
"startedAt": 0
}
},
"25b44bca9e45": {
"name": "hostPlatform",
"ordinal": 15,
"value": "darwin"
},
"36a96ddbd396": {
"name": "host.platform#1",
"ordinal": 12,
"json": "{\"id\":\"frame-4\",\"deviceToken\":\"recording-device\",\"method\":\"host.platform\"}"
},
"56ab81cb67dc": {
"name": "hostLabelById",
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": [["ssh:ssh-1", "SSH"]]
"value": []
},
"6338d57f282f": {
"repoColorsByName": [
@@ -293,46 +293,13 @@
"ordinal": 11,
"json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
"args": [
{
"name": "method",
"value": "ssh.listTargetSummaries"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"id": "frame-2",
"ok": true,
"result": {
"targets": [
{
"id": "ssh-1",
"label": "SSH"
}
]
}
}
}
"bea13a4a2e87": {
"name": "hostLabelById",
"ordinal": 14,
"value": [["ssh:ssh-1", "SSH"]]
},
"e62b46a04ba1": {
"c020f709d835": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "darwin",
"repoColorsByName": [
@@ -376,6 +343,45 @@
["Avatar", "repo-3"]
]
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
"args": [
{
"name": "method",
"value": "ssh.listTargetSummaries"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"id": "frame-2",
"ok": true,
"result": {
"targets": [
{
"id": "ssh-1",
"label": "SSH"
}
]
}
}
}
},
"eb79a9b3682a": {
"status": "fulfilled",
"startedAt": 0,
@@ -444,14 +450,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "e62b46a04ba1",
"state": "c020f709d835",
"effects": [
"19bf6d2469a6",
"ae27a5b525fa",
"77cbfd1f087c",
"6bc5e5b7a259",
"56ab81cb67dc",
"12ba3f41d4db"
"6063e534d9db",
"bea13a4a2e87",
"25b44bca9e45"
]
}
}
@@ -38,23 +38,6 @@
}
}
},
"071880b671a1": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"0c4296f215a4": {
"name": "settings.get#1",
"ordinal": 8,
@@ -95,6 +78,11 @@
}
}
},
"0ef3d910f42e": {
"name": "hostLabelById",
"ordinal": 29,
"value": [["ssh:ssh-1", "SSH"]]
},
"19b2979d7fc2": {
"name": "repo.list#1",
"ordinal": 2,
@@ -131,44 +119,10 @@
"ordinal": 4,
"value": []
},
"2a201bc09f96": {
"name": "ssh.listTargetSummaries#2",
"ordinal": 21,
"args": [
{
"name": "method",
"value": "ssh.listTargetSummaries"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"id": "frame-6",
"ok": true,
"result": {
"targets": [
{
"id": "ssh-1",
"label": "SSH"
}
]
}
}
}
"2053629911e7": {
"name": "repo.list#2",
"ordinal": 17,
"json": "{\"id\":\"frame-5\",\"deviceToken\":\"recording-device\",\"method\":\"repo.list\"}"
},
"2f1b95eac8f1": {
"name": "repoColorsByName",
@@ -178,27 +132,16 @@
["Remote", "#f97316"]
]
},
"339b07cb7b7e": {
"name": "repoHostIdByRepoId",
"ordinal": 20,
"value": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
]
},
"35a231ef3ff8": {
"name": "repoIdsByName",
"ordinal": 19,
"value": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"36a96ddbd396": {
"name": "host.platform#1",
"ordinal": 12,
"json": "{\"id\":\"frame-4\",\"deviceToken\":\"recording-device\",\"method\":\"host.platform\"}"
},
"376d3874239c": {
"name": "repoIconsByName",
"ordinal": 19,
"value": []
},
"4526bff18b74": {
"name": "repo.list#1",
"ordinal": 1,
@@ -246,37 +189,9 @@
}
}
},
"56ab81cb67dc": {
"name": "hostLabelById",
"ordinal": 13,
"value": [["ssh:ssh-1", "SSH"]]
},
"5b7bcd015aba": {
"name": "repoColorsByName",
"ordinal": 17,
"value": [
["Local", "#6366f1"],
["Remote", "#f97316"]
]
},
"6134b73f18d0": {
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"64986b5eb58e": {
"455855a85ab4": {
"name": "settings.get#2",
"ordinal": 22,
"ordinal": 23,
"args": [
{
"name": "method",
@@ -309,24 +224,240 @@
}
}
},
"64aa5287977c": {
"name": "hostLabelById",
"ordinal": 27,
"value": [["ssh:ssh-1", "SSH"]]
"4771e3dbbbcf": {
"name": "host.platform#2",
"ordinal": 24,
"args": [
{
"name": "method",
"value": "host.platform"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"id": "frame-8",
"ok": true,
"result": {
"platform": "linux"
}
}
}
},
"53226cb82ec3": {
"name": "hostPlatform",
"ordinal": 15,
"value": "linux"
},
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": []
},
"6134b73f18d0": {
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"668a7e313975": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 10,
"json": "{\"id\":\"frame-2\",\"deviceToken\":\"recording-device\",\"method\":\"ssh.listTargetSummaries\"}"
},
"673a2bbe62e3": {
"name": "hostPlatform",
"7e772c1c111d": {
"name": "repoIdsByName",
"ordinal": 5,
"value": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"8c5c812580ad": {
"name": "host.platform#2",
"ordinal": 27,
"json": "{\"id\":\"frame-8\",\"deviceToken\":\"recording-device\",\"method\":\"host.platform\"}"
},
"8ef3b348c179": {
"name": "repoHostIdByRepoId",
"ordinal": 6,
"value": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
]
},
"9270aeb7d9c6": {
"status": "pending",
"startedAt": 0
},
"96e0c54d86b0": {
"name": "settings.get#1",
"ordinal": 8,
"args": [
{
"name": "method",
"value": "settings.get"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "pending",
"startedAt": 0
}
},
"a67416f78b93": {
"name": "hostHealthById",
"ordinal": 28,
"value": []
},
"b428bce85ee7": {
"name": "settings.get#1",
"ordinal": 11,
"json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"bea13a4a2e87": {
"name": "hostLabelById",
"ordinal": 14,
"value": [["ssh:ssh-1", "SSH"]]
},
"c497d2d846c9": {
"name": "ssh.listTargetSummaries#2",
"ordinal": 25,
"json": "{\"id\":\"frame-6\",\"deviceToken\":\"recording-device\",\"method\":\"ssh.listTargetSummaries\"}"
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
"args": [
{
"name": "method",
"value": "ssh.listTargetSummaries"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"id": "frame-2",
"ok": true,
"result": {
"targets": [
{
"id": "ssh-1",
"label": "SSH"
}
]
}
}
}
},
"ceef481be25c": {
"name": "hostPlatform",
"ordinal": 30,
"value": "linux"
},
"7d3ba1e92188": {
"d51254d2537f": {
"name": "settings.get#2",
"ordinal": 26,
"json": "{\"id\":\"frame-7\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"d569b5b2500f": {
"name": "ssh.listTargetSummaries#2",
"ordinal": 22,
"args": [
{
"name": "method",
"value": "ssh.listTargetSummaries"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"id": "frame-6",
"ok": true,
"result": {
"targets": [
{
"id": "ssh-1",
"label": "SSH"
}
]
}
}
}
},
"da7cf9752395": {
"name": "repoColorsByName",
"ordinal": 18,
"value": [
["Local", "#6366f1"],
["Remote", "#f97316"]
]
},
"df78d2202264": {
"name": "repo.list#2",
"ordinal": 15,
"ordinal": 16,
"args": [
{
"name": "method",
@@ -371,22 +502,51 @@
}
}
},
"7e772c1c111d": {
"ea2ced0895f3": {
"name": "repoHostIdByRepoId",
"ordinal": 21,
"value": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
]
},
"eb79a9b3682a": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"$rpc": "undefined"
}
},
"eb885d2ceee5": {
"name": "repoIdsByName",
"ordinal": 5,
"ordinal": 20,
"value": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"8800889a5f18": {
"name": "host.platform#2",
"ordinal": 26,
"json": "{\"id\":\"frame-8\",\"deviceToken\":\"recording-device\",\"method\":\"host.platform\"}"
"f4667dda0187": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"8dd3e3e2a847": {
"fa585aceeec2": {
"name": "repo.list#2",
"ordinal": 15,
"ordinal": 16,
"args": [
{
"name": "method",
@@ -409,155 +569,6 @@
"status": "pending",
"startedAt": 0
}
},
"8ef3b348c179": {
"name": "repoHostIdByRepoId",
"ordinal": 6,
"value": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
]
},
"9270aeb7d9c6": {
"status": "pending",
"startedAt": 0
},
"96e0c54d86b0": {
"name": "settings.get#1",
"ordinal": 8,
"args": [
{
"name": "method",
"value": "settings.get"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "pending",
"startedAt": 0
}
},
"983e55643949": {
"name": "settings.get#2",
"ordinal": 25,
"json": "{\"id\":\"frame-7\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"b428bce85ee7": {
"name": "settings.get#1",
"ordinal": 11,
"json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"be773224294b": {
"name": "repoIconsByName",
"ordinal": 18,
"value": []
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
"args": [
{
"name": "method",
"value": "ssh.listTargetSummaries"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"id": "frame-2",
"ok": true,
"result": {
"targets": [
{
"id": "ssh-1",
"label": "SSH"
}
]
}
}
}
},
"d1f0a64c0651": {
"name": "ssh.listTargetSummaries#2",
"ordinal": 24,
"json": "{\"id\":\"frame-6\",\"deviceToken\":\"recording-device\",\"method\":\"ssh.listTargetSummaries\"}"
},
"de81371c7ac8": {
"name": "repo.list#2",
"ordinal": 16,
"json": "{\"id\":\"frame-5\",\"deviceToken\":\"recording-device\",\"method\":\"repo.list\"}"
},
"eb79a9b3682a": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"$rpc": "undefined"
}
},
"f9193cae5824": {
"name": "hostPlatform",
"ordinal": 14,
"value": "linux"
},
"fc50a8ac2e64": {
"name": "host.platform#2",
"ordinal": 23,
"args": [
{
"name": "method",
"value": "host.platform"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "fulfilled",
"startedAt": 0,
"settledAt": 0,
"value": {
"id": "frame-8",
"ok": true,
"result": {
"platform": "linux"
}
}
}
}
},
"recording": {
@@ -585,14 +596,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -605,14 +617,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -624,28 +637,29 @@
"c752e67787f9",
"0c4296f215a4",
"03c9a2ba60b9",
"8dd3e3e2a847"
"fa585aceeec2"
],
"payloads": [
"19b2979d7fc2",
"668a7e313975",
"b428bce85ee7",
"36a96ddbd396",
"de81371c7ac8"
"2053629911e7"
],
"settlements": {
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a",
"reload": "9270aeb7d9c6"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
},
@@ -657,40 +671,42 @@
"c752e67787f9",
"0c4296f215a4",
"03c9a2ba60b9",
"7d3ba1e92188",
"2a201bc09f96",
"64986b5eb58e",
"fc50a8ac2e64"
"df78d2202264",
"d569b5b2500f",
"455855a85ab4",
"4771e3dbbbcf"
],
"payloads": [
"19b2979d7fc2",
"668a7e313975",
"b428bce85ee7",
"36a96ddbd396",
"de81371c7ac8",
"d1f0a64c0651",
"983e55643949",
"8800889a5f18"
"2053629911e7",
"c497d2d846c9",
"d51254d2537f",
"8c5c812580ad"
],
"settlements": {
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a",
"reload": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824",
"5b7bcd015aba",
"be773224294b",
"35a231ef3ff8",
"339b07cb7b7e",
"64aa5287977c",
"673a2bbe62e3"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3",
"da7cf9752395",
"376d3874239c",
"eb885d2ceee5",
"ea2ced0895f3",
"a67416f78b93",
"0ef3d910f42e",
"ceef481be25c"
]
}
}
@@ -38,23 +38,6 @@
}
}
},
"071880b671a1": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"19b2979d7fc2": {
"name": "repo.list#1",
"ordinal": 2,
@@ -186,10 +169,15 @@
}
}
},
"56ab81cb67dc": {
"name": "hostLabelById",
"53226cb82ec3": {
"name": "hostPlatform",
"ordinal": 15,
"value": "linux"
},
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": [["ssh:ssh-1", "SSH"]]
"value": []
},
"6134b73f18d0": {
"repoColorsByName": [
@@ -262,6 +250,11 @@
"ordinal": 11,
"json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"bea13a4a2e87": {
"name": "hostLabelById",
"ordinal": 14,
"value": [["ssh:ssh-1", "SSH"]]
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
@@ -309,10 +302,23 @@
"$rpc": "undefined"
}
},
"f9193cae5824": {
"name": "hostPlatform",
"ordinal": 14,
"value": "linux"
"f4667dda0187": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
}
},
"recording": {
@@ -340,14 +346,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
}
@@ -9,6 +9,32 @@
"ordinal": 2,
"json": "{\"id\":\"frame-1\",\"deviceToken\":\"recording-device\",\"method\":\"repo.list\"}"
},
"1a160fc2d137": {
"name": "host.platform#1",
"ordinal": 9,
"args": [
{
"name": "method",
"value": "host.platform"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "pending",
"startedAt": 0
}
},
"1ff13ee8621c": {
"name": "repoIconsByName",
"ordinal": 4,
@@ -29,6 +55,11 @@
["Remote folder", "repo-2"]
]
},
"36a96ddbd396": {
"name": "host.platform#1",
"ordinal": 12,
"json": "{\"id\":\"frame-4\",\"deviceToken\":\"recording-device\",\"method\":\"host.platform\"}"
},
"4b6956e45bac": {
"name": "repo.list#1",
"ordinal": 1,
@@ -74,6 +105,110 @@
}
}
},
"4bf1ed33de14": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
"args": [
{
"name": "method",
"value": "ssh.listTargetSummaries"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "rejected",
"startedAt": 0,
"settledAt": 0,
"error": {
"category": "Error",
"message": "Connection closed",
"isRpcDeliveryUnknown": true
}
}
},
"53dea128b181": {
"name": "host.platform#1",
"ordinal": 9,
"args": [
{
"name": "method",
"value": "host.platform"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "rejected",
"startedAt": 0,
"settledAt": 0,
"error": {
"category": "Error",
"message": "Connection closed",
"isRpcDeliveryUnknown": true
}
}
},
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": []
},
"668a7e313975": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 10,
"json": "{\"id\":\"frame-2\",\"deviceToken\":\"recording-device\",\"method\":\"ssh.listTargetSummaries\"}"
},
"6a227ad27189": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
"args": [
{
"name": "method",
"value": "ssh.listTargetSummaries"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "pending",
"startedAt": 0
}
},
"9270aeb7d9c6": {
"status": "pending",
"startedAt": 0
},
"937107a86348": {
"name": "repoIdsByName",
"ordinal": 5,
@@ -82,6 +217,39 @@
["Remote folder", "repo-2"]
]
},
"96e0c54d86b0": {
"name": "settings.get#1",
"ordinal": 8,
"args": [
{
"name": "method",
"value": "settings.get"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "pending",
"startedAt": 0
}
},
"9d20695fdb34": {
"name": "hostPlatform",
"ordinal": 15,
"value": {
"$rpc": "null"
}
},
"a086cfd03185": {
"name": "repoHostIdByRepoId",
"ordinal": 6,
@@ -90,6 +258,48 @@
["repo-2", "ssh:ssh-1"]
]
},
"b428bce85ee7": {
"name": "settings.get#1",
"ordinal": 11,
"json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"daecdc0e521b": {
"name": "hostLabelById",
"ordinal": 14,
"value": []
},
"dd3998116e8e": {
"name": "settings.get#1",
"ordinal": 8,
"args": [
{
"name": "method",
"value": "settings.get"
},
{
"name": "params",
"value": {
"$rpc": "absent"
}
},
{
"name": "options",
"value": {
"$rpc": "absent"
}
}
],
"settlement": {
"status": "rejected",
"startedAt": 0,
"settledAt": 0,
"error": {
"category": "Error",
"message": "Connection closed",
"isRpcDeliveryUnknown": true
}
}
},
"eb79a9b3682a": {
"status": "fulfilled",
"startedAt": 0,
@@ -113,14 +323,35 @@
{
"id": "single-host-without-label-lookups",
"observation": {
"sender": ["4b6956e45bac"],
"payloads": ["19b2979d7fc2"],
"sender": ["4b6956e45bac", "6a227ad27189", "96e0c54d86b0", "1a160fc2d137"],
"payloads": ["19b2979d7fc2", "668a7e313975", "b428bce85ee7", "36a96ddbd396"],
"settlements": {
"mount": "eb79a9b3682a",
"load": "9270aeb7d9c6"
},
"state": "2bd489a9fa29",
"effects": ["fc0785cc0b08", "1ff13ee8621c", "937107a86348", "a086cfd03185"]
}
},
{
"id": "cleanup",
"observation": {
"sender": ["4b6956e45bac", "4bf1ed33de14", "dd3998116e8e", "53dea128b181"],
"payloads": ["19b2979d7fc2", "668a7e313975", "b428bce85ee7", "36a96ddbd396"],
"settlements": {
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "2bd489a9fa29",
"effects": ["fc0785cc0b08", "1ff13ee8621c", "937107a86348", "a086cfd03185"]
"effects": [
"fc0785cc0b08",
"1ff13ee8621c",
"937107a86348",
"a086cfd03185",
"6063e534d9db",
"daecdc0e521b",
"9d20695fdb34"
]
}
}
]
@@ -38,23 +38,6 @@
}
}
},
"071880b671a1": {
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
},
"19b2979d7fc2": {
"name": "repo.list#1",
"ordinal": 2,
@@ -151,10 +134,10 @@
}
}
},
"56ab81cb67dc": {
"name": "hostLabelById",
"ordinal": 13,
"value": [["ssh:ssh-1", "SSH"]]
"53226cb82ec3": {
"name": "hostPlatform",
"ordinal": 15,
"value": "linux"
},
"6021c58b2fd2": {
"name": "settings.get#1",
@@ -188,6 +171,11 @@
}
}
},
"6063e534d9db": {
"name": "hostHealthById",
"ordinal": 13,
"value": []
},
"6134b73f18d0": {
"repoColorsByName": [
["Local", "#6366f1"],
@@ -259,6 +247,11 @@
"ordinal": 11,
"json": "{\"id\":\"frame-3\",\"deviceToken\":\"recording-device\",\"method\":\"settings.get\"}"
},
"bea13a4a2e87": {
"name": "hostLabelById",
"ordinal": 14,
"value": [["ssh:ssh-1", "SSH"]]
},
"c752e67787f9": {
"name": "ssh.listTargetSummaries#1",
"ordinal": 7,
@@ -306,10 +299,23 @@
"$rpc": "undefined"
}
},
"f9193cae5824": {
"name": "hostPlatform",
"ordinal": 14,
"value": "linux"
"f4667dda0187": {
"hostHealthById": [],
"hostLabelById": [["ssh:ssh-1", "SSH"]],
"hostPlatform": "linux",
"repoColorsByName": [
["Local", "#6366f1"],
["Remote", "#f97316"]
],
"repoHostIdByRepoId": [
["repo-1", "local"],
["repo-2", "ssh:ssh-1"]
],
"repoIconsByName": [],
"repoIdsByName": [
["Local", "repo-1"],
["Remote", "repo-2"]
]
}
},
"recording": {
@@ -337,14 +343,15 @@
"mount": "eb79a9b3682a",
"load": "eb79a9b3682a"
},
"state": "071880b671a1",
"state": "f4667dda0187",
"effects": [
"2f1b95eac8f1",
"1ff13ee8621c",
"7e772c1c111d",
"8ef3b348c179",
"56ab81cb67dc",
"f9193cae5824"
"6063e534d9db",
"bea13a4a2e87",
"53226cb82ec3"
]
}
}
@@ -244,7 +244,32 @@ describe('memoized worktree rows', () => {
)
})
expect(textNodes()).toContain('openclaw')
expect(textNodes().some((text) => text.includes('Disconnected'))).toBe(false)
expect(renderer!.root.findAllByType('Server' as never)).toHaveLength(1)
await act(async () =>
renderer!.update(
createElement(ListRowHarness, {
item: {
...baseItem,
hostId: 'ssh:ssh-1',
hostContextLabel: 'openclaw',
hostContextHealthLabel: 'Disconnected'
},
now: 2_000
})
)
)
// Separate nodes: the name truncates while the health word stays whole.
expect(textNodes()).toEqual(expect.arrayContaining(['openclaw', '· Disconnected']))
const healthText = renderer!.root
.findAllByType('Text' as never)
.find((node) => node.props.children === '· Disconnected')
expect([healthText?.props.style].flat()).toContainEqual({ flexShrink: 0 })
const announcedBadges = renderer!.root.findAll(
(node) => node.props.accessibilityLabel === 'openclaw, Disconnected'
)
expect(announcedBadges).toHaveLength(1)
expect(renderer!.root.findAllByType('Monitor' as never)).toHaveLength(0)
await act(async () =>
+17 -1
View File
@@ -36,6 +36,8 @@ export type WorktreeListRowItem = {
hostContextLabel?: string
/** Resolved host for the display label; present when legacy rows omit hostId. */
hostContextHostId?: ExecutionHostId
/** The host's health word, e.g. "Disconnected"; absent while the host is healthy. */
hostContextHealthLabel?: string
repo: string
branch: string
displayName: string
@@ -165,7 +167,12 @@ function WorktreeListRowComponent<T extends WorktreeListRowItem>({
</View>
)}
{item.hostContextLabel ? (
<View style={[styles.childBadge, styles.hostBadge]}>
<View
style={[styles.childBadge, styles.hostBadge]}
accessibilityLabel={[item.hostContextLabel, item.hostContextHealthLabel]
.filter(Boolean)
.join(', ')}
>
{/* Rows from hosts that predate hostId stamping are local: a remote row always carries one. */}
{(parseExecutionHostId(item.hostContextHostId ?? item.hostId)?.kind ?? 'local') ===
'local' ? (
@@ -176,6 +183,12 @@ function WorktreeListRowComponent<T extends WorktreeListRowItem>({
<Text style={[styles.childBadgeText, styles.hostBadgeText]} numberOfLines={1}>
{item.hostContextLabel}
</Text>
{/* Why separate Text: the name truncates first so the health word stays readable. */}
{item.hostContextHealthLabel ? (
<Text style={[styles.childBadgeText, styles.hostHealthText]}>
{`· ${item.hostContextHealthLabel}`}
</Text>
) : null}
</View>
) : null}
{/* Repo glyph+name only when not already grouped under this repo;
@@ -341,6 +354,9 @@ const styles = StyleSheet.create({
hostBadgeText: {
flexShrink: 1
},
hostHealthText: {
flexShrink: 0
},
lineageToggle: {
alignSelf: 'flex-start',
flexDirection: 'row',
@@ -83,6 +83,20 @@ describe('host screen reply schemas', () => {
).toEqual([{ id: 't', label: 'T' }])
})
it('keeps SSH lifecycle fields raw and drops a malformed one without losing the target', () => {
expect(
hostSshTargetSummariesSchema.parse({
targets: [
{ id: 't', label: 'T', connected: false, connectionStatus: 'hibernating' },
{ id: 'u', label: 'U', connected: 'no', connectionStatus: 7 }
]
})
).toEqual([
{ id: 't', label: 'T', connected: false, connectionStatus: 'hibernating' },
{ id: 'u', label: 'U' }
])
})
it('answers the empty target list for a reply that is no object at all', () => {
// Why: the label write runs before the platform write in the same sequence, so a throw here
// would take the platform down with it. readSshTargets answered [] for every one of these.
@@ -93,7 +93,15 @@ export const hostSshTargetSummariesSchema = z
.looseObject({
targets: salvagedOptional(
'targets',
salvagingArray(z.looseObject({ id: z.string(), label: z.string() }))
salvagingArray(
z.looseObject({
id: z.string(),
label: z.string(),
// Read raw: an arm a newer desktop adds must leave the badge as it is, not read as a verdict.
connected: salvagedOptional('connected', z.boolean()),
connectionStatus: salvagedOptional('connectionStatus', z.string())
})
)
)
})
.transform((reply) => reply.targets ?? [])
@@ -48,6 +48,7 @@ function screenState(clientRef: ClientRef, applied: boolean[]) {
'setCatalogError',
'setError',
'setHostLabelById',
'setHostHealthById',
'setHostName',
'setHostPlatform',
'setHostStoredDescriptor',
@@ -0,0 +1,135 @@
import { createElement } from 'react'
import { act, create } from 'react-test-renderer'
import { describe, expect, it, vi } from 'vitest'
vi.mock('../cache/worktree-cache', () => ({
getCachedWorktrees: () => null,
setCachedWorktrees: () => {}
}))
vi.mock('../cache/repo-cache', () => ({ setCachedRepos: () => {} }))
import { FakeSession } from '../transport/mobile-endpoint-supervisor-test-fakes'
import type { RpcResponse } from '../transport/types'
import type { Worktree } from '../worktree/workspace-list-types'
import { useHostDisplayWorktrees } from './use-host-display-worktrees'
import { useHostRepoMetadata } from './use-host-repo-metadata'
import { useHostScreenState } from './use-host-screen-state'
function reply(result: unknown): RpcResponse {
return { id: 'reply', ok: true, result, _meta: { runtimeId: 'runtime' } }
}
function row(worktreeId: string, repoId: string): Worktree {
return {
workspaceKind: 'git',
worktreeId,
repoId,
repo: repoId,
branch: 'main',
displayName: worktreeId,
path: `/home/me/${worktreeId}`,
liveTerminalCount: 0,
hasAttachedPty: false,
preview: '',
unread: false,
isPinned: false,
linkedPR: null
}
}
// Drives the screen's own state, metadata refresh and row projection against one desktop reply set.
async function displayedRows(args: {
repos: { id: string; displayName: string; connectionId?: string }[]
rows: Worktree[]
sshTarget: Record<string, unknown>
/** The catalog a second refresh answers, once the first has applied. */
thenRepos?: { id: string; displayName: string; connectionId?: string }[]
}): Promise<Worktree[]> {
let repos = args.repos
const client = new FakeSession('connected')
client.sendRequest.mockImplementation(async (method: string) => {
switch (method) {
case 'repo.list':
return reply({ repos })
case 'ssh.listTargetSummaries':
return reply({ targets: [{ id: 'devbox', label: 'devbox', ...args.sshTarget }] })
case 'host.platform':
return reply({ platform: 'darwin' })
default:
return reply({})
}
})
const seen: { rows: Worktree[]; refresh?: (options: { force: boolean }) => Promise<void> } = {
rows: []
}
let setWorktrees: ((rows: Worktree[]) => void) | undefined
function Probe(): null {
const state = useHostScreenState('host-1', undefined)
state.clientRef.current = client
setWorktrees = state.setWorktrees
seen.refresh = useHostRepoMetadata({ client, connState: 'connected', hostId: 'host-1', state })
seen.rows = useHostDisplayWorktrees('connected', state)
return null
}
await act(async () => {
create(createElement(Probe))
})
await act(async () => {
setWorktrees?.(args.rows)
await seen.refresh?.({ force: true })
})
if (args.thenRepos) {
repos = args.thenRepos
await act(async () => {
await seen.refresh?.({ force: true })
})
}
return seen.rows
}
describe('SSH host health on the host list rows', () => {
it('names an unreachable SSH host with its health even when every row is on it', async () => {
const rows = await displayedRows({
repos: [{ id: 'repo-ssh', displayName: 'api', connectionId: 'devbox' }],
rows: [row('a', 'repo-ssh'), row('b', 'repo-ssh')],
sshTarget: { connected: false, connectionStatus: 'disconnected' }
})
expect(rows.map((r) => [r.hostContextLabel, r.hostContextHealthLabel])).toEqual([
['devbox', 'Disconnected'],
['devbox', 'Disconnected']
])
})
it('carries the health beside the label in a mixed-host list', async () => {
const rows = await displayedRows({
repos: [
{ id: 'repo-local', displayName: 'web' },
{ id: 'repo-ssh', displayName: 'api', connectionId: 'devbox' }
],
rows: [row('a', 'repo-local'), row('b', 'repo-ssh')],
sshTarget: { connected: false, connectionStatus: 'reconnecting' }
})
expect(rows.map((r) => r.hostContextHealthLabel)).toEqual([undefined, 'Connecting'])
})
it('drops the badge once the SSH host leaves the catalog', async () => {
const rows = await displayedRows({
repos: [{ id: 'repo-ssh', displayName: 'api', connectionId: 'devbox' }],
rows: [{ ...row('a', 'repo-ssh'), hostId: 'ssh:devbox' }],
sshTarget: { connected: false, connectionStatus: 'disconnected' },
thenRepos: [{ id: 'repo-local', displayName: 'web' }]
})
expect(rows[0].hostContextLabel).toBeUndefined()
expect(rows[0].hostContextHealthLabel).toBeUndefined()
})
it('keeps a healthy single-host list bare', async () => {
const rows = await displayedRows({
repos: [{ id: 'repo-ssh', displayName: 'api', connectionId: 'devbox' }],
rows: [row('a', 'repo-ssh')],
sshTarget: { connected: true, connectionStatus: 'connected' }
})
expect(rows[0].hostContextLabel).toBeUndefined()
expect(rows[0].hostContextHealthLabel).toBeUndefined()
})
})
@@ -0,0 +1,33 @@
import { useMemo } from 'react'
import type { ConnectionState } from '../transport/types'
import { applyWorktreeHostContextLabels } from '../worktree/worktree-host-context-labels'
import { applyWorktreeRowDisplayState } from '../worktree/worktree-host-row-identity'
import type { HostScreenState } from './use-host-screen-state'
/** The rows the host list renders: the live or last-known catalog with display state and host badges. */
export function useHostDisplayWorktrees(connState: ConnectionState, state: HostScreenState) {
return useMemo(() => {
// Why: live `worktrees` is authoritative only while connected; under the amber
// mount default, connecting/handshaking must keep the pre-reconnect list too.
const base = connState === 'connected' ? state.worktrees : state.lastKnownWorktrees
return applyWorktreeHostContextLabels(
applyWorktreeRowDisplayState(base, state.sleptIds, state.optimisticActiveWorktreeIdentity),
{
repoHostIdByRepoId: state.repoHostIdByRepoId,
hostLabelById: state.hostLabelById,
hostPlatform: state.hostPlatform,
hostHealthById: state.hostHealthById
}
)
}, [
connState,
state.worktrees,
state.lastKnownWorktrees,
state.sleptIds,
state.optimisticActiveWorktreeIdentity,
state.repoHostIdByRepoId,
state.hostLabelById,
state.hostPlatform,
state.hostHealthById
])
}
@@ -1,6 +1,6 @@
import { optionalSettingsRead } from '../transport/settings-read-operations'
import { useCallback } from 'react'
import { getRepoExecutionHostId } from '../../../src/shared/execution-host'
import { getRepoExecutionHostId, parseExecutionHostId } from '../../../src/shared/execution-host'
import { setCachedRepos } from '../cache/repo-cache'
import type { RpcAcceptedResult } from '../transport/rpc-accepted-result'
import type { RpcClient } from '../transport/rpc-client'
@@ -10,6 +10,7 @@ import {
buildHostLabelById,
buildRepoHostIdByRepoId
} from '../worktree/worktree-host-context-labels'
import { buildSshHostHealthById } from '../worktree/worktree-host-health'
import {
hostPlatformRead,
hostRepoCatalogRead,
@@ -58,6 +59,7 @@ export function useHostRepoMetadata(args: {
fetchRepoMetadataPendingRef,
repoMetadataFetchedAtRef,
setHostLabelById,
setHostHealthById,
setHostPlatform,
setRepoColorsByName,
setRepoHostIdByRepoId,
@@ -116,11 +118,12 @@ export function useHostRepoMetadata(args: {
)
setRepoIdsByName(new Map(catalog.map((repo) => [repo.displayName, repo.id])))
setRepoHostIdByRepoId(buildRepoHostIdByRepoId(catalog))
// Why: rows only name their host when the list spans hosts, so a single-host
// catalog never pays for the label lookups. Counted over repos, not the id-keyed
// map: one repo id registered on two hosts is two hosts.
// Why: rows name their host when the list spans hosts or an SSH host may be unhealthy,
// so a local-only catalog never pays for the label lookups. Counted over repos, not the
// id-keyed map: one repo id registered on two hosts is two hosts.
const hostIds = new Set(catalog.map((repo) => getRepoExecutionHostId(repo)))
if (hostIds.size > 1) {
const hasSshHost = [...hostIds].some((id) => parseExecutionHostId(id)?.kind === 'ssh')
if (hostIds.size > 1 || hasSshHost) {
const [sshTargets, hostSettings, hostPlatform] = await Promise.all([
settledMetadataReply(() => hostSshTargetSummariesRead.request(requestClient)),
optionalSettingsRead.request(requestClient).catch(() => null),
@@ -132,16 +135,22 @@ export function useHostRepoMetadata(args: {
const hostSettingsResult = hostSettings
? optionalSettingsRead.interpret(hostSettings)
: null
const sshTargetSummaries =
acceptedMetadata(sshTargets, hostSshTargetSummariesRead.interpret) ?? []
setHostHealthById(buildSshHostHealthById(sshTargetSummaries))
setHostLabelById(
buildHostLabelById({
sshTargets:
acceptedMetadata(sshTargets, hostSshTargetSummariesRead.interpret) ?? [],
sshTargets: sshTargetSummaries,
hostSettingOverrides: readHostSettingOverrides(
hostSettingsResult?.accepted ? hostSettingsResult.value : undefined
)
})
)
setHostPlatform(acceptedMetadata(hostPlatform, hostPlatformRead.interpret) ?? null)
} else {
// Why: a host that left the catalog must not keep badging rows that still name it.
setHostHealthById(new Map())
setHostLabelById(new Map())
}
} while (fetchRepoMetadataPendingRef.current.has(requestClient))
} catch {
@@ -14,9 +14,8 @@ import {
useReconnectAttempt,
useRelayRecoveryStatus
} from '../transport/client-context-connection-metrics'
import { applyWorktreeRowDisplayState } from '../worktree/worktree-host-row-identity'
import { applyWorktreeHostContextLabels } from '../worktree/worktree-host-context-labels'
import { useWorkspaceSections } from '../worktree/use-workspace-sections'
import { useHostDisplayWorktrees } from './use-host-display-worktrees'
import { useHostRepoMetadata } from './use-host-repo-metadata'
import { useHostScreenIdentity } from './use-host-screen-identity'
import { useHostScreenState } from './use-host-screen-state'
@@ -102,28 +101,7 @@ export function useHostScreenController({
}
const showNewWorktree = resolvedRouteActionState.showNewWorktree
const displayWorktrees = useMemo(() => {
// Why: live `worktrees` is authoritative only while connected; under the amber
// mount default, connecting/handshaking must keep the pre-reconnect list too.
const base = connState === 'connected' ? state.worktrees : state.lastKnownWorktrees
return applyWorktreeHostContextLabels(
applyWorktreeRowDisplayState(base, state.sleptIds, state.optimisticActiveWorktreeIdentity),
{
repoHostIdByRepoId: state.repoHostIdByRepoId,
hostLabelById: state.hostLabelById,
hostPlatform: state.hostPlatform
}
)
}, [
connState,
state.worktrees,
state.lastKnownWorktrees,
state.sleptIds,
state.optimisticActiveWorktreeIdentity,
state.repoHostIdByRepoId,
state.hostLabelById,
state.hostPlatform
])
const displayWorktrees = useHostDisplayWorktrees(connState, state)
const sectionsResult = useWorkspaceSections({
displayWorktrees,
sortMode: state.sortMode,
@@ -18,6 +18,7 @@ export function useHostScreenIdentity(args: {
setCatalogError,
setError,
setHostLabelById,
setHostHealthById,
setHostName,
setHostPlatform,
setHostStoredDescriptor,
@@ -62,6 +63,7 @@ export function useHostScreenIdentity(args: {
setRepoIconsByName(new Map())
setRepoHostIdByRepoId(new Map())
setHostLabelById(new Map())
setHostHealthById(new Map())
setHostPlatform(null)
setShowPinnedInGroups(false)
repoMetadataFetchedAtRef.current = 0
@@ -1,5 +1,6 @@
import { useRef, useState } from 'react'
import type { ExecutionHostId } from '../../../src/shared/execution-host'
import type { ExecutionHostHealth } from '../../../src/shared/execution-host-health'
import type { WorkspaceStatusDefinition } from '../../../src/shared/worktree/types'
import { getCachedWorktrees } from '../cache/worktree-cache'
import { createInitialHostRouteActionState } from '../host-route-action-state'
@@ -71,6 +72,9 @@ export function useHostScreenState(hostId: string | undefined, action: string |
new Map()
)
const [hostLabelById, setHostLabelById] = useState<Map<ExecutionHostId, string>>(new Map())
const [hostHealthById, setHostHealthById] = useState<Map<ExecutionHostId, ExecutionHostHealth>>(
new Map()
)
const [hostPlatform, setHostPlatform] = useState<NodeJS.Platform | null>(null)
const [showSortPicker, setShowSortPicker] = useState(false)
const [showGroupPicker, setShowGroupPicker] = useState(false)
@@ -113,6 +117,7 @@ export function useHostScreenState(hostId: string | undefined, action: string |
filters,
groupMode,
hostLabelById,
hostHealthById,
hostName,
hostPlatform,
hostStoredDescriptor,
@@ -138,6 +143,7 @@ export function useHostScreenState(hostId: string | undefined, action: string |
setFilters,
setGroupMode,
setHostLabelById,
setHostHealthById,
setHostName,
setHostPlatform,
setHostStoredDescriptor,
@@ -7,9 +7,9 @@ import {
repoSetupHooksSchema,
repoSparsePresetListSchema,
repoSparsePresetSaveSchema,
SSH_CONNECTION_STATUS,
sshConnectionStateSchema
} from './workspace-source-reply-schema'
import { SSH_CONNECTION_STATUS } from '../transport/ssh-connection-status-arms'
// Pins the SSH status degrade, the error tri-state beside it, and the preset requirement.
@@ -1,11 +1,6 @@
import { z } from 'zod'
import type { SshConnectionStatus } from '../../../src/shared/ssh-types'
import {
hostUnionArms,
openEnum,
salvagedOptional,
salvagingArray
} from '../../../src/shared/zod-salvage'
import { openEnum, salvagedOptional, salvagingArray } from '../../../src/shared/zod-salvage'
import { SSH_CONNECTION_STATUS } from '../transport/ssh-connection-status-arms'
// The repo and SSH reads the workspace-create drawer runs. Checked against
// src/main/runtime/rpc/methods/ssh.ts:30-46 (getPublicSshState, SshConnectionState in
@@ -13,18 +8,6 @@ import {
// answer a bare `string[]`), and repo.ts:87-103/:184-192 (the sparse preset envelopes, the ref
// search and the orca.yaml hooks).
// Pinned to the host's own union through hostUnionArms: an arm added or dropped host-side fails tsc.
export const SSH_CONNECTION_STATUS = hostUnionArms<SshConnectionStatus>({
disconnected: true,
connecting: true,
'auth-failed': true,
'deploying-relay': true,
connected: true,
reconnecting: true,
'reconnection-failed': true,
error: true
})
const sourceText = (name: string) => salvagedOptional(name, z.string())
/**
@@ -0,0 +1,20 @@
import type { SshConnectionStatus } from '../../../src/shared/ssh-types'
import { hostUnionArms } from '../../../src/shared/zod-salvage'
// Pinned to the host's own union through hostUnionArms: an arm added or dropped host-side fails tsc.
export const SSH_CONNECTION_STATUS = hostUnionArms<SshConnectionStatus>({
disconnected: true,
connecting: true,
'auth-failed': true,
'deploying-relay': true,
connected: true,
reconnecting: true,
'reconnection-failed': true,
error: true
})
const KNOWN_SSH_CONNECTION_STATUSES: ReadonlySet<string> = new Set(SSH_CONNECTION_STATUS)
export function isSshConnectionStatus(status: string): status is SshConnectionStatus {
return KNOWN_SSH_CONNECTION_STATUSES.has(status)
}
@@ -113,6 +113,21 @@ describe('startHostWorktreeRefresh', () => {
expect(fetchRepoMetadata).toHaveBeenCalledWith({ force: true, queueIfInFlight: true })
})
it('re-reads repo metadata, which carries SSH host health, on sshStateChanged', () => {
start()
fetchWorktrees.mockClear()
fetchRepoMetadata.mockClear()
eventListener?.({
type: 'sshStateChanged',
targetId: 'ssh-1',
state: { targetId: 'ssh-1', status: 'reconnecting' }
})
expect(fetchWorktrees).not.toHaveBeenCalled()
expect(fetchRepoMetadata).toHaveBeenCalledWith({ force: true, queueIfInFlight: true })
})
it('refreshes worktrees on worktreesChanged and both snapshots after stream replay', () => {
start()
fetchWorktrees.mockClear()
@@ -74,6 +74,9 @@ export function startHostWorktreeRefresh({
void fetchRepoMetadata({ force: true, queueIfInFlight: true })
} else if (event.type === 'worktreesChanged') {
void fetchWorktrees()
} else if (event.type === 'sshStateChanged') {
// Why: host badges carry SSH health, read with the labels from ssh.listTargetSummaries.
void fetchRepoMetadata({ force: true, queueIfInFlight: true })
}
}
)
@@ -13,6 +13,8 @@ export type Worktree = {
hostContextLabel?: string
/** Resolved host for the display label; present when legacy rows omit hostId. */
hostContextHostId?: ExecutionHostId
/** Display-only; the host's health word beside its label, absent while the host is healthy. */
hostContextHealthLabel?: string
repo: string
branch: string
displayName: string
@@ -86,7 +86,8 @@ describe('getWorktreeHostContextLabels', () => {
const sources = {
repoHostIdByRepoId: new Map(),
hostLabelById: new Map([[sshHostId, 'openclaw']]),
hostPlatform: 'darwin' as const
hostPlatform: 'darwin' as const,
hostHealthById: new Map()
}
it('returns nothing for a single-host list', () => {
@@ -95,6 +96,28 @@ describe('getWorktreeHostContextLabels', () => {
expect(applyWorktreeHostContextLabels(rows, sources)).toBe(rows)
})
it('names an unhealthy host even in a single-host list, and only that host', () => {
const rows = [worktree({ hostId: sshHostId, worktreeId: 'a' })]
const unhealthy = applyWorktreeHostContextLabels(rows, {
...sources,
hostHealthById: new Map([[sshHostId, 'connecting']])
})
expect(unhealthy.map((row) => [row.hostContextLabel, row.hostContextHealthLabel])).toEqual([
['openclaw', 'Connecting']
])
expect(
applyWorktreeHostContextLabels(rows, {
...sources,
hostHealthById: new Map([[sshHostId, 'available']])
})
).toBe(rows)
const otherHostUnhealthy = applyWorktreeHostContextLabels(rows, {
...sources,
hostHealthById: new Map([['ssh:x', 'error']])
})
expect(otherHostUnhealthy[0].hostContextLabel).toBeUndefined()
})
it('names every row by host once the list spans hosts', () => {
const rows = [
worktree({ hostId: 'local', worktreeId: 'a' }),
@@ -111,6 +134,34 @@ describe('getWorktreeHostContextLabels', () => {
])
})
it('adds the health word only for hosts the desktop reports as unhealthy', () => {
const rows = [
worktree({ hostId: 'local', worktreeId: 'a' }),
worktree({ hostId: sshHostId, worktreeId: 'b' }),
worktree({ hostId: 'ssh:healthy', worktreeId: 'c' }),
worktree({ hostId: 'runtime:env-1', worktreeId: 'd' }),
worktree({ repoId: 'repo-ssh', worktreeId: 'e' })
]
const labeled = applyWorktreeHostContextLabels(rows, {
...sources,
repoHostIdByRepoId: buildRepoHostIdByRepoId([
{ id: 'repo-ssh', connectionId: 'ssh-1785104650217-eduhep' }
]),
hostHealthById: new Map([
['local', 'local'],
[sshHostId, 'disconnected'],
['ssh:healthy', 'available']
])
})
expect(labeled.map((row) => row.hostContextHealthLabel)).toEqual([
undefined,
'Disconnected',
undefined,
undefined,
'Disconnected'
])
})
it('names the local host from the paired host platform, not the phone', () => {
const rows = [
worktree({ hostId: 'local', worktreeId: 'a' }),
@@ -4,13 +4,18 @@ import {
normalizeExecutionHostId,
type ExecutionHostId
} from '../../../src/shared/execution-host'
import { getMixedHostContextLabels as getSharedMixedHostContextLabels } from '../../../src/shared/worktree/host-context-labels'
import {
getHostContextLabel,
getMixedHostContextLabels as getSharedMixedHostContextLabels
} from '../../../src/shared/worktree/host-context-labels'
import { composeWorktreeHostIdentity } from '../../../src/shared/worktree/host-qualified-identity'
export {
buildHostLabelById,
getHostContextLabel
} from '../../../src/shared/worktree/host-context-labels'
import type { ExecutionHostHealth } from '../../../src/shared/execution-host-health'
import type { Worktree } from './workspace-list-types'
import { getHostHealthBadgeLabel } from './worktree-host-health'
export type HostLabelSources = {
/** Host id per repo id from repo.list; rows from hosts that predate `hostId` fall back to it. */
@@ -19,6 +24,8 @@ export type HostLabelSources = {
hostLabelById: ReadonlyMap<ExecutionHostId, string>
/** The paired host's own platform; the phone's platform must never name the desktop. */
hostPlatform: NodeJS.Platform | null
/** Health per host the desktop reports one for; an absent host keeps the bare label. */
hostHealthById: ReadonlyMap<ExecutionHostId, ExecutionHostHealth>
}
export function buildRepoHostIdByRepoId(
@@ -72,20 +79,27 @@ export function applyWorktreeHostContextLabels(
sources: HostLabelSources
): Worktree[] {
const labels = getWorktreeHostContextLabels(worktrees, sources)
if (!labels) {
// Why: the desktop card shows SSH status on any host count, so an unhealthy host is named even alone.
const anyUnhealthy = [...sources.hostHealthById.values()].some(getHostHealthBadgeLabel)
if (!labels && !anyUnhealthy) {
return worktrees
}
return worktrees.map((worktree) => {
const hostContextLabel = labels.get(
getResolvedWorktreeRowIdentity(worktree, sources.repoHostIdByRepoId)
const hostContextHostId = resolveWorktreeHostId(worktree, sources.repoHostIdByRepoId)
const hostContextHealthLabel = getHostHealthBadgeLabel(
sources.hostHealthById.get(hostContextHostId)
)
const hostContextLabel = labels
? labels.get(getResolvedWorktreeRowIdentity(worktree, sources.repoHostIdByRepoId))
: hostContextHealthLabel && getHostContextLabel(hostContextHostId, sources)
if (!hostContextLabel) {
return worktree
}
return {
...worktree,
hostContextLabel,
hostContextHostId: resolveWorktreeHostId(worktree, sources.repoHostIdByRepoId)
hostContextHostId,
...(hostContextHealthLabel ? { hostContextHealthLabel } : {})
}
})
}
@@ -0,0 +1,46 @@
import { describe, expect, it } from 'vitest'
import { buildSshHostHealthById, getHostHealthBadgeLabel } from './worktree-host-health'
describe('buildSshHostHealthById', () => {
it('derives each SSH host health from its lifecycle, keyed by canonical host id', () => {
const health = buildSshHostHealthById([
{ id: 'up', connected: true, connectionStatus: 'connected' },
{ id: 'relay', connected: false, connectionStatus: 'deploying-relay' },
{ id: 'retry', connected: false, connectionStatus: 'reconnecting' },
{ id: 'down', connected: false, connectionStatus: 'disconnected' },
{ id: 'auth', connected: false, connectionStatus: 'auth-failed' },
{ id: 'never', connected: false },
{ id: 'ssh:canonical', connected: false, connectionStatus: 'connecting' }
])
expect(Object.fromEntries(health)).toEqual({
'ssh:up': 'available',
'ssh:relay': 'connecting',
'ssh:retry': 'connecting',
'ssh:down': 'disconnected',
'ssh:auth': 'error',
// Same verdict as the desktop sidebar for a target with no lifecycle state yet.
'ssh:never': 'disconnected',
'ssh:canonical': 'connecting'
})
})
it('reports nothing for a desktop that predates lifecycle fields or a status it cannot read', () => {
const health = buildSshHostHealthById([
{ id: 'old-desktop' },
{ id: 'future', connected: false, connectionStatus: 'hibernating' }
])
expect(health.size).toBe(0)
})
})
describe('getHostHealthBadgeLabel', () => {
it('uses the desktop sidebar words for unhealthy hosts only', () => {
expect(getHostHealthBadgeLabel('disconnected')).toBe('Disconnected')
expect(getHostHealthBadgeLabel('connecting')).toBe('Connecting')
expect(getHostHealthBadgeLabel('error')).toBe('Needs attention')
expect(getHostHealthBadgeLabel('blocked')).toBe('Update needed')
expect(getHostHealthBadgeLabel('available')).toBeUndefined()
expect(getHostHealthBadgeLabel('local')).toBeUndefined()
expect(getHostHealthBadgeLabel(undefined)).toBeUndefined()
})
})
@@ -0,0 +1,39 @@
import type { ExecutionHostId } from '../../../src/shared/execution-host'
import {
getExecutionHostHealthLabel,
getSshConnectionHealth,
type ExecutionHostHealth
} from '../../../src/shared/execution-host-health'
import { sshTargetSummaryHostId } from '../../../src/shared/worktree/host-context-labels'
import { isSshConnectionStatus } from '../transport/ssh-connection-status-arms'
/**
* Health per SSH host, derived exactly as the desktop sidebar derives it. A desktop that predates
* `connected` reports no lifecycle, and an unknown status is no verdict: both leave the host out.
*/
export function buildSshHostHealthById(
sshTargets: readonly { id: string; connected?: boolean; connectionStatus?: string }[]
): Map<ExecutionHostId, ExecutionHostHealth> {
const health = new Map<ExecutionHostId, ExecutionHostHealth>()
for (const target of sshTargets) {
const status = target.connectionStatus
if (
target.connected === undefined ||
(status !== undefined && !isSshConnectionStatus(status))
) {
continue
}
health.set(sshTargetSummaryHostId(target.id), getSshConnectionHealth(status))
}
return health
}
/** The word a row's host badge adds; a healthy or local host keeps the bare name. */
export function getHostHealthBadgeLabel(
health: ExecutionHostHealth | undefined
): string | undefined {
if (health === undefined || health === 'local' || health === 'available') {
return undefined
}
return getExecutionHostHealthLabel(health)
}
@@ -11,6 +11,7 @@ import {
buildExecutionHostRegistry,
type ExecutionHostHealth
} from '../../../../shared/execution-host-registry'
import { getExecutionHostHealthLabel } from '../../../../shared/execution-host-health'
import {
expandEquivalentExecutionHostIds,
pickerExecutionHosts
@@ -162,22 +163,7 @@ export function getCheckedHostRows<T extends SidebarHostOption>(
}
export function getSidebarHostHealthLabel(health: SidebarHostScopeOption['health']): string {
switch (health) {
case 'local':
return 'Local'
case 'available':
return 'Connected'
case 'connecting':
return 'Connecting'
case 'blocked':
return 'Update needed'
case 'disconnected':
return 'Disconnected'
case 'error':
return 'Needs attention'
case 'mixed':
return 'Mixed'
}
return health === 'mixed' ? 'Mixed' : getExecutionHostHealthLabel(health)
}
/**
+47
View File
@@ -0,0 +1,47 @@
import type { SshConnectionStatus } from './ssh-types'
export type ExecutionHostHealth =
| 'local'
| 'available'
| 'connecting'
| 'blocked'
| 'disconnected'
| 'error'
/** An SSH host's health; a target with no lifecycle state has never connected. */
export function getSshConnectionHealth(
status: SshConnectionStatus | undefined
): ExecutionHostHealth {
switch (status) {
case 'connected':
return 'available'
case 'connecting':
case 'deploying-relay':
case 'reconnecting':
return 'connecting'
case 'auth-failed':
case 'error':
case 'reconnection-failed':
return 'error'
case 'disconnected':
case undefined:
return 'disconnected'
}
}
export function getExecutionHostHealthLabel(health: ExecutionHostHealth): string {
switch (health) {
case 'local':
return 'Local'
case 'available':
return 'Connected'
case 'connecting':
return 'Connecting'
case 'blocked':
return 'Update needed'
case 'disconnected':
return 'Disconnected'
case 'error':
return 'Needs attention'
}
}
+3 -26
View File
@@ -20,14 +20,9 @@ import type { RuntimeEnvironmentSource } from './runtime-environments'
import type { GlobalSettings } from './global-settings-types'
import type { Repo } from './repo-types'
import { annotateManagedOrcadExecutionHosts } from './managed-orcad-execution-host'
import { getSshConnectionHealth, type ExecutionHostHealth } from './execution-host-health'
export type ExecutionHostHealth =
| 'local'
| 'available'
| 'connecting'
| 'blocked'
| 'disconnected'
| 'error'
export type { ExecutionHostHealth } from './execution-host-health'
export type ExecutionHostRegistryEntry = {
id: ExecutionHostId
@@ -113,24 +108,6 @@ function runtimeControlHealth(
}
}
function sshHealth(state: SshConnectionState | undefined): ExecutionHostHealth {
switch (state?.status) {
case 'connected':
return 'available'
case 'connecting':
case 'deploying-relay':
case 'reconnecting':
return 'connecting'
case 'auth-failed':
case 'error':
case 'reconnection-failed':
return 'error'
case 'disconnected':
case undefined:
return 'disconnected'
}
}
function setHost(
hosts: Map<ExecutionHostId, ExecutionHostRegistryEntry>,
entry: ExecutionHostRegistryEntry
@@ -302,7 +279,7 @@ export function buildExecutionHostRegistry(args: {
kind: 'ssh',
label: args.sshTargetLabels?.get(targetId) || targetId,
detail: 'SSH',
health: sshHealth(state),
health: getSshConnectionHealth(state?.status),
connectionStatus: state?.status
})
}
+8 -7
View File
@@ -40,10 +40,14 @@ export function getHostContextLabel(
}
/**
* Build labels for SSH targets and apply persisted display-name overrides.
* Target summaries have appeared both as raw target ids and canonical `ssh:` ids
* across protocol versions, so accept either representation.
* The host id an SSH target summary names. Summaries have carried both raw target ids and
* canonical `ssh:` ids across protocol versions, so accept either representation.
*/
export function sshTargetSummaryHostId(targetId: string): ExecutionHostId {
return normalizeExecutionHostId(targetId) ?? toSshExecutionHostId(targetId)
}
/** Build labels for SSH targets and apply persisted display-name overrides. */
export function buildHostLabelById(args: {
sshTargets: readonly { id: string; label: string }[]
hostSettingOverrides: unknown
@@ -54,10 +58,7 @@ export function buildHostLabelById(args: {
if (!target.id.trim() || !label) {
continue
}
const hostId = normalizeExecutionHostId(target.id) ?? toSshExecutionHostId(target.id)
if (hostId) {
labels.set(hostId, label)
}
labels.set(sshTargetSummaryHostId(target.id), label)
}
const overrides =
args.hostSettingOverrides && typeof args.hostSettingOverrides === 'object'