[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled

This commit is contained in:
2026-09-13 18:24:01 +08:00
commit 3c72efcb7f
3255 changed files with 907009 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
"use strict";
/**
* Merge two scoped snapshots without letting an older cross-scope copy
* overwrite newer connection state. Metadata revisions are assigned by the
* main-process bridge when a renderer update arrives.
*
* @param {Record<string, unknown> | null | undefined} previous
* @param {Record<string, unknown> | null | undefined} fallback
* @returns {Record<string, unknown> | null}
*/
function mergeRetentionMeta(previous, fallback) {
if (!previous && !fallback) return null;
if (!previous) return fallback && typeof fallback === "object" ? fallback : null;
if (!fallback || typeof fallback !== "object") return previous;
const previousRevision = Number.isSafeInteger(previous._revision) ? previous._revision : 0;
const fallbackRevision = Number.isSafeInteger(fallback._revision) ? fallback._revision : 0;
// Unversioned direct helper inputs retain the historical fallback-wins
// behavior. Bridge-owned metadata is always versioned.
const fallbackIsNewer = fallbackRevision >= previousRevision;
const newer = fallbackIsNewer ? fallback : previous;
const older = fallbackIsNewer ? previous : fallback;
const connected = Object.prototype.hasOwnProperty.call(newer, "connected")
? newer.connected !== false
: older.connected !== false;
return {
...older,
...newer,
hostname: newer.hostname || older.hostname,
label: newer.label || older.label,
os: newer.os || older.os,
username: newer.username || older.username,
protocol: newer.protocol || older.protocol,
shellType: newer.shellType || older.shellType,
deviceType: newer.deviceType || older.deviceType,
hostId: newer.hostId || older.hostId,
hostChain: Array.isArray(newer.hostChain) ? newer.hostChain : older.hostChain,
// Explicit empty arrays in the newer snapshot clear stopped forwards.
activePortForwards: Array.isArray(newer.activePortForwards)
? newer.activePortForwards
: older.activePortForwards,
connected,
...(Math.max(previousRevision, fallbackRevision) > 0
? { _revision: Math.max(previousRevision, fallbackRevision) }
: {}),
};
}
/**
* Keep host_open-owned sessions in a chat scope when a full metadata replace
* would otherwise drop them (e.g. AIChatSidePanel pushing only the current
* terminal tab after a mid-turn host_open).
*
* Empty incoming lists are treated as authoritative clears and are not retained.
*
* @param {{
* incomingSessions: Array<Record<string, unknown>>,
* ownedSessionIds: string[],
* previousById?: Map<string, Record<string, unknown>> | null,
* findFallbackMeta?: ((sessionId: string) => Record<string, unknown> | null | undefined) | null,
* }} args
* @returns {Array<Record<string, unknown>>}
*/
function retainOwnedSessions({
incomingSessions,
ownedSessionIds,
previousById = null,
findFallbackMeta = null,
}) {
if (!Array.isArray(incomingSessions) || incomingSessions.length === 0) {
return incomingSessions;
}
if (!Array.isArray(ownedSessionIds) || ownedSessionIds.length === 0) {
return incomingSessions;
}
const byId = new Map();
for (const entry of incomingSessions) {
if (!entry || typeof entry !== "object" || !entry.sessionId) continue;
byId.set(String(entry.sessionId), entry);
}
for (const ownedIdRaw of ownedSessionIds) {
const ownedId = typeof ownedIdRaw === "string" ? ownedIdRaw.trim() : "";
if (!ownedId || byId.has(ownedId)) continue;
const previous = previousById?.get?.(ownedId) || null;
// Always consult fallback — a stale previous connected:false must not
// block a fresher cross-scope snapshot (e.g. External MCP / other tab).
const fallback = typeof findFallbackMeta === "function"
? findFallbackMeta(ownedId)
: null;
const meta = mergeRetentionMeta(previous, fallback);
if (!meta || typeof meta !== "object") continue;
byId.set(ownedId, {
sessionId: ownedId,
hostname: meta.hostname || "",
label: meta.label || "",
os: meta.os || "",
username: meta.username || "",
protocol: meta.protocol || "",
shellType: meta.shellType || "",
deviceType: meta.deviceType || "",
connected: meta.connected !== false,
hostId: meta.hostId || "",
hostChain: Array.isArray(meta.hostChain) ? meta.hostChain : [],
activePortForwards: Array.isArray(meta.activePortForwards) ? meta.activePortForwards : [],
...(Number.isSafeInteger(meta._revision) ? { _revision: meta._revision } : {}),
});
}
return Array.from(byId.values());
}
module.exports = { retainOwnedSessions, mergeRetentionMeta };