mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-11-10 16:21:22 +00:00
* feat(system-manager): add container runtime switcher and kubectl pods Keep the existing Docker tab and select docker, podman, nerdctl, or Kubernetes from runtimes detected on the host. Kubernetes replaces the switcher with context and namespace selectors in the same panel. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): address container runtime review findings Move the runtime adapter into the domain layer, keep a context namespace when namespace listing is forbidden, and emit PowerShell or cmd startup commands for Kubernetes shell, logs, and describe. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): cover Windows container popups and stale namespaces Run container shell and logs through the host shell's inspect wrapper on PowerShell and cmd, and reset the namespace when a remembered Kubernetes context is no longer present. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): parse kubectl JSON after banners and scope inspect cache Skip bracketed banners before kubectl JSON, and include the container runtime in image and container inspect cache keys. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): parse Podman image lists emitted as JSON arrays Podman applies {{json .}} to the whole image slice. Accept that array, including Names and byte sizes, and keep Docker's JSON lines. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): parse Podman stats arrays Accept Podman's stats JSON array and its id/cpu_percent fields, and keep Docker's one-stat-per-line output. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): list every Podman image tag Expand each name in a Podman image's Names array into its own row so extra tags stay visible and searchable. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): quote kubectl list and delete for the session shell Namespace, pod, and delete commands follow PowerShell or cmd quoting when the session shell is not POSIX, so apostrophes in a context name survive local PowerShell. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): drop renamed runtime launch commands from shell history Container popups now probe with _nc_rt_err and also cover podman, nerdctl, and kubectl. History sanitizers still required _nc_docker_err, so those launches stayed in persisted history. Confirm-dialog resets also follow the selected runtime. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): sum Podman interface stats and quote kubectl for the executor Podman {{json .}} stats keep per-interface counters on Network, so the details panel now sums RxBytes and TxBytes. Background kubectl runs in powershell.exe on local Windows even when the terminal is cmd, so those commands are quoted for that executor instead of the interactive shell. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): remove a selected image tag instead of the shared id Podman rows that share one image id were all deleted with rmi <id>, which either fails while other tags remain or drops every name. Tagged rows now run rmi repository:tag; dangling images still use the id. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): reject cmd kubectl arguments that contain percent signs Interactive cmd.exe expands %VAR% inside double quotes, so a context such as prod-%USERNAME% would be rewritten before kubectl sees it. Cmd popups now refuse that argument. PowerShell quoting still preserves the percent. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * refactor(system-manager): move runtime selection into an application hook Persisted source, context, and namespace state plus the kubectl discovery effects now live in useContainerRuntimeSelection. DockerManagerTab only renders the switcher and panels. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): offer kubectl shell only for running containers Succeeded and failed pods have no running container, and a completed init container cannot accept exec. Shell targets now come from container statuses that are running; logs still include init containers. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): keep Windows popup commands out of shell history PowerShell and cmd container popups inspect then run, and kubectl popups are typed directly. History filtering only matched the POSIX sh -c wrapper, so those launches were stored as user commands. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): mark Windows popups instead of matching kubectl syntax Filtering kubectl --context logs and describe also dropped commands the user typed. Windows popups now carry __NC_POPUP__, and ordinary kubectl lines stay in history. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): reject cmd arguments that contain delayed-expansion marks cmd.exe with /V:ON expands !VAR! inside double quotes. Contexts such as prod!USER! are refused for cmd popups, same as percent signs. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): hide raw nerdctl and unreachable cluster errors Only offer nerdctl after a short info probe succeeds, or when the failure is a socket permission error that sudo can still recover. Map dead containerd and unreachable kube API errors to short localized messages and keep the CLI text in the log. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): show terminating pods and ephemeral containers A deletion timestamp is Terminating even while the phase is still Running. Ephemeral containers are included in the logs list, and a running one is a shell target. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): keep the runtime select on Kubernetes and avoid covering it Kubernetes uses the same compact source menu as Docker, with context and namespace beside it. Shell popups open in the free part of the window so they no longer sit on top of the pod badges. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): restore the saved engine when Kubernetes disappears A host that was on Podman before Kubernetes keeps Podman if kubectl is gone, instead of falling back to Docker and overwriting that choice. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): avoid the visible system panel when others are parked A hidden parking-host panel can be the first system-manager match and has a zero-size rect. Scan every match and pass the first panel that actually has size so the shell popup still sits beside the open panel. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): keep a runtime choice across probe gaps and show podman ports A failed nerdctl or kubectl probe was saved as the fallback engine, so the previous choice never returned. Reconciliation now restores the stored source when it is detected again, and automatic fallbacks are not written back. Podman ps port mappings and exposed ports are formatted into the same display string the container detail strip already shows. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): show a pod's Evicted reason Pod status.reason is the eviction signal, while the phase stays Failed and the container often reports Error. Use that reason after a container waiting state and before the generic phase so the badge stays Evicted. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): keep an avoided shell popup inside the work area When the source window sits partly off-screen, clamping a slot back onto the display could cover the system panel, and the fallback then used the raw slot origin. Place the popup in the on-screen part of the slot instead. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> * fix(system-manager): left-align the runtime selector row The Kubernetes context, namespace, and runtime selects sat on the right of the header, so they did not line up with the search field. Keep the same padding, let the context select fill the remaining width, and leave the runtime and namespace selects at their natural width. Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
40 lines
1.7 KiB
TypeScript
40 lines
1.7 KiB
TypeScript
import type { ContainerRuntimeId, ContainerSourceId } from '../../../domain/systemManager/containerRuntime';
|
|
import { isContainerSource } from '../../../domain/systemManager/containerRuntime';
|
|
import { STORAGE_KEY_CONTAINER_RUNTIME } from '../../../infrastructure/config/storageKeys';
|
|
import { localStorageAdapter } from '../../../infrastructure/persistence/localStorageAdapter';
|
|
|
|
export interface ContainerRuntimePreference {
|
|
source: ContainerSourceId;
|
|
engine?: ContainerRuntimeId;
|
|
context?: string;
|
|
namespace?: string;
|
|
}
|
|
|
|
type PreferenceStore = Record<string, ContainerRuntimePreference>;
|
|
|
|
const CONTAINER_ENGINES = new Set<ContainerRuntimeId>(['docker', 'podman', 'nerdctl']);
|
|
|
|
function readStore(): PreferenceStore {
|
|
const value = localStorageAdapter.read<PreferenceStore>(STORAGE_KEY_CONTAINER_RUNTIME);
|
|
return value && typeof value === 'object' ? value : {};
|
|
}
|
|
|
|
export function readContainerRuntimePreference(hostId: string): ContainerRuntimePreference | null {
|
|
if (!hostId) return null;
|
|
const entry = readStore()[hostId];
|
|
if (!entry || !isContainerSource(entry.source)) return null;
|
|
return {
|
|
source: entry.source,
|
|
engine: entry.engine && CONTAINER_ENGINES.has(entry.engine) ? entry.engine : undefined,
|
|
context: typeof entry.context === 'string' ? entry.context : undefined,
|
|
namespace: typeof entry.namespace === 'string' ? entry.namespace : undefined,
|
|
};
|
|
}
|
|
|
|
export function writeContainerRuntimePreference(hostId: string, entry: ContainerRuntimePreference): void {
|
|
if (!hostId || !isContainerSource(entry.source)) return;
|
|
const store = readStore();
|
|
store[hostId] = entry;
|
|
localStorageAdapter.write(STORAGE_KEY_CONTAINER_RUNTIME, store);
|
|
}
|