@exagone313/dsh-podman 0.2.0-rc.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -2
- package/README.zh.md +14 -2
- package/cordis.patch.yml +58 -0
- package/dist/approval-reasons.d.ts +3 -4
- package/dist/approval-reasons.js +40 -49
- package/dist/approval-reasons.test.js +43 -15
- package/dist/approval.js +27 -10
- package/dist/approval.test.js +165 -34
- package/dist/card-route.d.ts +3 -2
- package/dist/card-route.js +154 -42
- package/dist/card-route.test.js +85 -43
- package/dist/card-test-support.js +39 -66
- package/dist/client/ContainerCard.d.ts +1 -1
- package/dist/client/ContainerCard.js +92 -50
- package/dist/client/card-protocol.d.ts +6 -3
- package/dist/client/container-card-caches.js +11 -6
- package/dist/client/container-card-controller.d.ts +16 -18
- package/dist/client/container-card-controller.js +92 -40
- package/dist/client/container-card-create-modal.d.ts +2 -2
- package/dist/client/container-card-create-modal.js +13 -5
- package/dist/client/container-card-default-env.d.ts +10 -0
- package/dist/client/container-card-default-env.js +69 -0
- package/dist/client/container-card-directory.d.ts +2 -2
- package/dist/client/container-card-directory.js +12 -4
- package/dist/client/container-card-editors.d.ts +3 -3
- package/dist/client/container-card-editors.js +104 -32
- package/dist/client/container-card-images.d.ts +4 -4
- package/dist/client/container-card-images.js +19 -6
- package/dist/client/container-card-paths.d.ts +3 -3
- package/dist/client/container-card-paths.js +18 -11
- package/dist/client/container-card-row.d.ts +10 -6
- package/dist/client/container-card-row.js +82 -13
- package/dist/client/container-card-secrets.d.ts +3 -3
- package/dist/client/container-card-secrets.js +8 -6
- package/dist/client/container-card-shared.d.ts +4 -17
- package/dist/client/container-card-shared.js +9 -25
- package/dist/client/container-card-styles.d.ts +2 -8
- package/dist/client/container-card-styles.js +14 -52
- package/dist/client/container-card-volumes.d.ts +2 -2
- package/dist/client/container-card-volumes.js +9 -5
- package/dist/client/container-card-workspace.d.ts +8 -6
- package/dist/client/container-card-workspace.js +9 -3
- package/dist/client/directory-picker.js +2 -1
- package/dist/client/index.js +13141 -2036
- package/dist/client/locales.d.ts +6 -1
- package/dist/client/locales.js +106 -38
- package/dist/client/podman-terminal-guide.d.ts +11 -0
- package/dist/client/podman-terminal-guide.js +208 -0
- package/dist/client/podman-terminal-title.d.ts +7 -0
- package/dist/client/podman-terminal-title.js +30 -0
- package/dist/client/podman-terminal.d.ts +26 -0
- package/dist/client/podman-terminal.js +412 -0
- package/dist/client/read-only-approval.d.ts +2 -2
- package/dist/client/read-only-approval.js +13 -3
- package/dist/client/slot-contract.d.ts +0 -11
- package/dist/client/terminal-preference.d.ts +26 -0
- package/dist/client/terminal-preference.js +67 -0
- package/dist/client/terminal-protocol.d.ts +85 -0
- package/dist/client/terminal-protocol.js +14 -0
- package/dist/client/terminal-tab.d.ts +60 -0
- package/dist/client/terminal-tab.js +35 -0
- package/dist/client/terminal-targets.d.ts +33 -0
- package/dist/client/terminal-targets.js +65 -0
- package/dist/client/terminal-titles.d.ts +23 -0
- package/dist/client/terminal-titles.js +52 -0
- package/dist/client/terminal-transport.d.ts +63 -0
- package/dist/client/terminal-transport.js +207 -0
- package/dist/client/tool-views.js +215 -49
- package/dist/container-env.d.ts +11 -0
- package/dist/container-env.js +96 -0
- package/dist/container-env.test.d.ts +1 -0
- package/dist/container-env.test.js +93 -0
- package/dist/containers.test.js +196 -18
- package/dist/daemons.test.js +18 -4
- package/dist/dsh-version.d.ts +1 -0
- package/dist/dsh-version.js +46 -0
- package/dist/env-rows.d.ts +14 -0
- package/dist/env-rows.js +52 -0
- package/dist/env-rows.test.d.ts +1 -0
- package/dist/env-rows.test.js +43 -0
- package/dist/fs-provider.d.ts +1 -0
- package/dist/fs-provider.js +26 -12
- package/dist/fs-provider.test.js +51 -10
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.js +2 -2
- package/dist/grpc/proto/dshctl/v1/control.proto +11 -1
- package/dist/grpc/proto/dshguest/v1/guest.proto +5 -0
- package/dist/grpc/runtime-client.d.ts +3 -1
- package/dist/grpc/runtime-client.js +90 -17
- package/dist/guest-rpc.d.ts +15 -19
- package/dist/guest-rpc.js +289 -70
- package/dist/guest-rpc.test.d.ts +1 -0
- package/dist/guest-rpc.test.js +241 -0
- package/dist/guest-terminal.d.ts +30 -0
- package/dist/guest-terminal.js +196 -0
- package/dist/images.test.js +10 -3
- package/dist/index.d.ts +11 -16
- package/dist/index.js +42 -36
- package/dist/locales.test.d.ts +1 -0
- package/dist/locales.test.js +34 -0
- package/dist/misc.test.js +38 -10
- package/dist/mount-enums.js +2 -1
- package/dist/mount-input.d.ts +2 -0
- package/dist/mount-input.js +38 -22
- package/dist/mounts.test.js +81 -11
- package/dist/naming.test.d.ts +1 -0
- package/dist/naming.test.js +28 -0
- package/dist/output-reader.js +36 -4
- package/dist/package-deps.test.d.ts +1 -0
- package/dist/package-deps.test.js +49 -0
- package/dist/paths.test.js +4 -2
- package/dist/plugin-meta.test.d.ts +1 -0
- package/dist/plugin-meta.test.js +29 -0
- package/dist/project-path.js +33 -7
- package/dist/project-path.test.js +14 -0
- package/dist/prompts.d.ts +0 -4
- package/dist/prompts.js +15 -84
- package/dist/read-only-shell.js +3 -1
- package/dist/read-only-shell.test.js +80 -25
- package/dist/runtime-client.test.d.ts +1 -0
- package/dist/runtime-client.test.js +53 -0
- package/dist/secrets.test.js +21 -6
- package/dist/settings-commands.test.js +61 -14
- package/dist/settings-create.test.js +32 -10
- package/dist/settings-default-env.test.d.ts +1 -0
- package/dist/settings-default-env.test.js +175 -0
- package/dist/settings-mounts.test.js +46 -7
- package/dist/settings-schema.d.ts +6 -11
- package/dist/settings-schema.js +4 -8
- package/dist/settings-schema.test.d.ts +1 -0
- package/dist/settings-schema.test.js +35 -0
- package/dist/settings-workspaces.test.js +38 -63
- package/dist/spill-store.d.ts +1 -0
- package/dist/spill-store.js +17 -4
- package/dist/spill-store.test.js +31 -8
- package/dist/subprocess.d.ts +4 -0
- package/dist/subprocess.js +148 -162
- package/dist/subprocess.test.js +118 -8
- package/dist/terminal-preference.test.d.ts +1 -0
- package/dist/terminal-preference.test.js +62 -0
- package/dist/terminal-route.d.ts +10 -0
- package/dist/terminal-route.js +270 -0
- package/dist/terminal-route.test.d.ts +1 -0
- package/dist/terminal-route.test.js +265 -0
- package/dist/terminal-sessions.d.ts +69 -0
- package/dist/terminal-sessions.js +252 -0
- package/dist/terminal-shells.d.ts +22 -0
- package/dist/terminal-shells.js +99 -0
- package/dist/terminal-tab.test.d.ts +1 -0
- package/dist/terminal-tab.test.js +58 -0
- package/dist/terminal-targets.test.d.ts +1 -0
- package/dist/terminal-targets.test.js +43 -0
- package/dist/terminal-titles.test.d.ts +1 -0
- package/dist/terminal-titles.test.js +36 -0
- package/dist/test-support.d.ts +35 -5
- package/dist/test-support.js +91 -29
- package/dist/tool-defs.js +19 -4
- package/dist/tool-handlers.js +80 -28
- package/dist/tool-params.js +19 -5
- package/dist/version-compat.d.ts +4 -0
- package/dist/version-compat.js +29 -0
- package/dist/version-compat.test.d.ts +1 -0
- package/dist/version-compat.test.js +27 -0
- package/dist/volumes.test.js +1 -1
- package/dist/workspace-binding.d.ts +19 -10
- package/dist/workspace-binding.js +252 -78
- package/dist/workspace-binding.test.js +202 -27
- package/docs/architecture.md +71 -20
- package/docs/architecture.zh.md +62 -12
- package/docs/configuration.md +61 -20
- package/docs/configuration.zh.md +53 -19
- package/docs/development-prompt.md +72 -0
- package/docs/development-prompt.zh.md +69 -0
- package/docs/development.md +184 -29
- package/docs/development.zh.md +165 -26
- package/docs/install-dsh-and-dsh-podman.md +24 -21
- package/docs/install-dsh-and-dsh-podman.zh.md +20 -21
- package/docs/uninstall.md +83 -0
- package/docs/uninstall.zh.md +79 -0
- package/docs/update.md +120 -0
- package/docs/update.zh.md +114 -0
- package/docs/usage.md +108 -61
- package/docs/usage.zh.md +76 -38
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +58 -25
- package/quadlet/dsh-podman-orchestrator.container +46 -0
- package/quadlet/dsh.container +35 -0
- package/LICENSE.pkg +0 -17103
- package/dist/preferences.d.ts +0 -6
- package/dist/preferences.js +0 -27
package/dist/client/locales.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export declare const NS = "podman";
|
|
2
|
-
export type ContainerPluginKey = "cardTitle" | "cardDescription" | "
|
|
2
|
+
export type ContainerPluginKey = "cardTitle" | "cardDescription" | "versionMismatchMajor" | "versionMismatchMinor" | "versionsTitle" | "orchestrator" | "versionUnknown" | "dsh" | "copyVersions" | "copied" | "copyFailed" | "reload" | "notice" | "defaultImage" | "defaultImageHint" | "defaultEnvironment" | "defaultEnvironmentHint" | "gitIdentity" | "gitName" | "gitEmail" | "gitIdentityHint" | "applyDefaults" | "confirmApplyDefaults" | "clear" | "save" | "discard" | "workspacesTitle" | "noContainers" | "createContainer" | "containerName" | "image" | "status" | "created" | "projects" | "remove" | "removePod" | "confirmRemovePod" | "recreate" | "recreateWithImage" | "imagesTitle" | "imageId" | "imageTag" | "builtAt" | "packages" | "volumesTitle" | "createVolume" | "removeVolume" | "volumeName" | "secretsTitle" | "createSecret" | "secretName" | "secretCharset" | "selectImage" | "setSecret" | "removeSecret" | "removeImage" | "rebuildImage" | "rebuildAllImages" | "buildImage" | "build" | "buildImageTitle" | "pullImage" | "setDefaultImage" | "setDefaultImageTitle" | "baseImagesTitle" | "customImagesTitle" | "primitive" | "packageManager" | "parent" | "cancel" | "removeTag" | "env" | "secretEnv" | "envTitle" | "envKey" | "envValue" | "addEnv" | "removeEnv" | "secretLength" | "containerSecretsTitle" | "attachSecret" | "secretEnvName" | "detachSecret" | "none" | "unavailable" | "busy" | "confirmTitle" | "confirm" | "confirmRemoveContainer" | "confirmRecreate" | "confirmRemoveImage" | "confirmRebuildImage" | "confirmRebuildAllImages" | "confirmRemoveVolume" | "confirmSetSecret" | "confirmRemoveSecret" | "confirmDetachSecret" | "mountsTitle" | "addMount" | "mountKind" | "mountProject" | "mountProjectPath" | "browse" | "browseTitle" | "browseSelect" | "browseLoading" | "browseError" | "browseUnavailable" | "browseHidden" | "browseTruncated" | "browseOutsideRoot" | "mountDestination" | "pathsTitle" | "noPaths" | "editPaths" | "addPath" | "add" | "moveUp" | "moveDown" | "apply" | "dragToReorder" | "remountWaiting" | "remountApprove" | "remountReject" | "mountVolume" | "mountSecret" | "mountTmpfs" | "mountAt" | "mountMode" | "readOnly" | "readWrite" | "mountReadOnlySuffix" | "mountReadWriteSuffix" | "remountReadOnly" | "remountReadWrite" | "confirmRemountReadOnly" | "confirmRemountReadWrite" | "confirmRemoveMount" | "cachesTitle" | "noCaches" | "cacheUsage" | "cacheKeepLatest" | "confirmCacheKeepLatest" | "cacheRemoveAll" | "confirmCacheRemoveAll" | "addContainer" | "invalidContainerName" | "containerNameTaken" | "invalidName" | "invalidImageId" | "terminalSignal" | "terminalExitCode" | "terminalNoExitCode" | "terminalRunning" | "terminalFailed" | "terminalDone" | "terminalNoOutput" | "terminalCollapseAria" | "terminalExpandAria" | "terminalExpandRest" | "toolTitle_container_bash" | "toolTitle_container_exec" | "toolTitle_container_read" | "toolTitle_container_write" | "toolTitle_container_edit" | "toolTitle_container_glob" | "toolTitle_container_grep" | "toolTitle_container_list" | "toolTitle_container_start" | "toolTitle_container_recreate" | "toolTitle_container_remove" | "toolTitle_container_mount_list" | "toolTitle_container_mount_add" | "toolTitle_container_mount_remove" | "toolTitle_container_mount_update" | "toolTitle_container_path_set" | "toolTitle_container_path_add" | "toolTitle_container_path_remove" | "toolTitle_container_secret_add" | "toolTitle_container_secret_remove" | "toolTitle_image_list" | "toolTitle_image_get" | "toolTitle_image_build" | "toolTitle_image_rebuild" | "toolTitle_image_rebuild_all" | "toolTitle_image_remove" | "toolTitle_volume_list" | "toolTitle_volume_create" | "toolTitle_volume_remove" | "toolTitle_secret_list" | "toolTitle_secret_create" | "toolTitle_secret_remove" | "toolTitle_daemon_start" | "toolTitle_daemon_list" | "toolTitle_daemon_logs" | "toolTitle_daemon_restart" | "toolTitle_daemon_stop" | "terminalTabTitle" | "terminalGuideTitle" | "terminalGuideDescription" | "terminalShortcut" | "terminalShortcutNoSession" | "terminalContainer" | "terminalShell" | "terminalDefaultContainer" | "terminalStart" | "terminalConnect" | "terminalReconnect" | "terminalStatusConnecting" | "terminalStatusRunning" | "terminalStatusExited" | "terminalStatusDetached" | "terminalNoShells" | "terminalShellsFailed" | "terminalLoading";
|
|
3
|
+
/**
|
|
4
|
+
* Translate one key, interpolating `{name}` placeholders when given. Components
|
|
5
|
+
* that build dialog copy declare this so they can name their subject.
|
|
6
|
+
*/
|
|
7
|
+
export type Translate = (key: ContainerPluginKey, params?: Record<string, string>) => string;
|
|
3
8
|
export declare const en: Record<ContainerPluginKey, string>;
|
|
4
9
|
export declare const zh: Record<ContainerPluginKey, string>;
|
|
5
10
|
declare module "@deepseek-ai/dsh-client-ui-slots" {
|
package/dist/client/locales.js
CHANGED
|
@@ -5,34 +5,45 @@ export const NS = "podman";
|
|
|
5
5
|
export const en = {
|
|
6
6
|
cardTitle: "dsh-podman",
|
|
7
7
|
cardDescription: "Manage the guest containers and their images.",
|
|
8
|
+
versionMismatchMajor: "This plugin's major version differs from the orchestrator's; update the dsh image or the orchestrator image so both match.",
|
|
9
|
+
versionMismatchMinor: "This plugin and the orchestrator have compatible but different versions; consider updating both images.",
|
|
10
|
+
versionsTitle: "Versions",
|
|
11
|
+
orchestrator: "dsh-podman-orchestrator",
|
|
12
|
+
versionUnknown: "unknown",
|
|
13
|
+
dsh: "dsh",
|
|
14
|
+
copyVersions: "Copy versions",
|
|
15
|
+
copied: "Copied",
|
|
16
|
+
copyFailed: "Copy failed",
|
|
8
17
|
reload: "Reload this view",
|
|
9
|
-
reloading: "Reloading…",
|
|
10
18
|
notice: "Notice",
|
|
11
|
-
configTitle: "Configuration",
|
|
12
19
|
defaultImage: "Default image",
|
|
13
|
-
socketsRoot: "Sockets root",
|
|
14
|
-
projectsRoot: "Projects root",
|
|
15
20
|
defaultImageHint: "Image used when a workspace has no image of its own.",
|
|
21
|
+
defaultEnvironment: "Default environment",
|
|
22
|
+
defaultEnvironmentHint: "Seeded into a container when it is created. Edit a container's own environment and recreate it to change or remove a value for that container.",
|
|
23
|
+
gitIdentity: "Git identity",
|
|
24
|
+
gitName: "Name",
|
|
25
|
+
gitEmail: "Email",
|
|
26
|
+
gitIdentityHint: "Fills GIT_AUTHOR_NAME/EMAIL and GIT_COMMITTER_NAME/EMAIL for new containers, so commits made inside them are attributed to you.",
|
|
27
|
+
applyDefaults: "Apply default environment variables",
|
|
28
|
+
confirmApplyDefaults: "Add the default environment variables to the containers that are missing them? Matching running containers are recreated (their processes and daemons stop); existing values are kept and stopped containers are left alone.",
|
|
29
|
+
clear: "Clear",
|
|
16
30
|
save: "Save",
|
|
17
31
|
discard: "Discard",
|
|
18
32
|
workspacesTitle: "Workspaces",
|
|
19
33
|
noContainers: "This workspace has no containers yet.",
|
|
20
34
|
createContainer: "Create container",
|
|
21
|
-
containersTitle: "Containers",
|
|
22
35
|
containerName: "Container",
|
|
23
|
-
workspace: "Workspace",
|
|
24
36
|
image: "Image",
|
|
25
37
|
status: "Status",
|
|
26
38
|
created: "Created",
|
|
27
39
|
projects: "Projects",
|
|
28
40
|
remove: "Remove",
|
|
29
41
|
removePod: "Remove pod",
|
|
30
|
-
confirmRemovePod: "Remove
|
|
42
|
+
confirmRemovePod: "Remove the pod of workspace “{workspace}” and all its containers? Volume and project data is kept.",
|
|
31
43
|
recreate: "Recreate",
|
|
32
44
|
recreateWithImage: "Recreate with image",
|
|
33
45
|
imagesTitle: "Images",
|
|
34
46
|
imageId: "Image ID",
|
|
35
|
-
baseImage: "Base image",
|
|
36
47
|
imageTag: "Tag",
|
|
37
48
|
builtAt: "Built at",
|
|
38
49
|
packages: "Packages",
|
|
@@ -80,15 +91,15 @@ export const en = {
|
|
|
80
91
|
busy: "Working…",
|
|
81
92
|
confirmTitle: "Confirm action",
|
|
82
93
|
confirm: "Confirm",
|
|
83
|
-
confirmRemoveContainer: "Remove
|
|
84
|
-
confirmRecreate: "Recreate
|
|
85
|
-
confirmRemoveImage: "Remove
|
|
86
|
-
confirmRebuildImage: "Rebuild
|
|
94
|
+
confirmRemoveContainer: "Remove container “{container}” from workspace “{workspace}”?",
|
|
95
|
+
confirmRecreate: "Recreate container “{container}” in workspace “{workspace}”? Its ephemeral state is lost.",
|
|
96
|
+
confirmRemoveImage: "Remove image “{image}”? Containers using it must be recreated from another image.",
|
|
97
|
+
confirmRebuildImage: "Rebuild image “{image}” in place?",
|
|
87
98
|
confirmRebuildAllImages: "Rebuild every image in dependency order (base first)?",
|
|
88
|
-
confirmRemoveVolume: "Remove
|
|
89
|
-
confirmSetSecret: "Overwrite
|
|
90
|
-
confirmRemoveSecret: "Remove
|
|
91
|
-
confirmDetachSecret: "Detach
|
|
99
|
+
confirmRemoveVolume: "Remove volume “{volume}” and its data?",
|
|
100
|
+
confirmSetSecret: "Overwrite the value of secret “{secret}”?",
|
|
101
|
+
confirmRemoveSecret: "Remove secret “{secret}”? Containers using it must drop it first.",
|
|
102
|
+
confirmDetachSecret: "Detach secret “{secret}” from environment variable {env}?",
|
|
92
103
|
mountsTitle: "Mounts",
|
|
93
104
|
addMount: "Add mount",
|
|
94
105
|
mountKind: "Kind",
|
|
@@ -118,14 +129,18 @@ export const en = {
|
|
|
118
129
|
remountReject: "Reject",
|
|
119
130
|
mountVolume: "Volume",
|
|
120
131
|
mountSecret: "Secret",
|
|
132
|
+
mountTmpfs: "tmpfs",
|
|
133
|
+
mountAt: "at",
|
|
121
134
|
mountMode: "Mode",
|
|
122
135
|
readOnly: "Read-only",
|
|
123
136
|
readWrite: "Read-write",
|
|
137
|
+
mountReadOnlySuffix: "(ro)",
|
|
138
|
+
mountReadWriteSuffix: "(rw)",
|
|
124
139
|
remountReadOnly: "Remount as read-only",
|
|
125
140
|
remountReadWrite: "Remount as read-write",
|
|
126
|
-
confirmRemountReadOnly: "Remount
|
|
127
|
-
confirmRemountReadWrite: "Remount
|
|
128
|
-
confirmRemoveMount: "Remove
|
|
141
|
+
confirmRemountReadOnly: "Remount {mount} as read-only and recreate the container?",
|
|
142
|
+
confirmRemountReadWrite: "Remount {mount} as read-write and recreate the container?",
|
|
143
|
+
confirmRemoveMount: "Remove mount {mount} from the container and recreate it?",
|
|
129
144
|
cachesTitle: "Package caches",
|
|
130
145
|
noCaches: "No package cache is configured.",
|
|
131
146
|
cacheUsage: "{size} · {n} files",
|
|
@@ -140,6 +155,7 @@ export const en = {
|
|
|
140
155
|
invalidImageId: "Start with a letter, digit, or '_'; only letters, digits, '.', '_', '-', '/', ':' (max 128).",
|
|
141
156
|
terminalSignal: "signal {signal}",
|
|
142
157
|
terminalExitCode: "exit code {code}",
|
|
158
|
+
terminalNoExitCode: "no exit code",
|
|
143
159
|
terminalRunning: "Running",
|
|
144
160
|
terminalFailed: "Failed",
|
|
145
161
|
terminalDone: "Done",
|
|
@@ -184,38 +200,67 @@ export const en = {
|
|
|
184
200
|
toolTitle_daemon_logs: "Daemon logs",
|
|
185
201
|
toolTitle_daemon_restart: "Restart daemon",
|
|
186
202
|
toolTitle_daemon_stop: "Stop daemon",
|
|
203
|
+
terminalTabTitle: "Terminal",
|
|
204
|
+
terminalGuideTitle: "New terminal",
|
|
205
|
+
terminalGuideDescription: "Run commands in the Session workspace",
|
|
206
|
+
terminalShortcut: "New terminal",
|
|
207
|
+
terminalShortcutNoSession: "Select a session first",
|
|
208
|
+
terminalContainer: "Container",
|
|
209
|
+
terminalShell: "Shell",
|
|
210
|
+
terminalDefaultContainer: "Default container",
|
|
211
|
+
terminalStart: "Start",
|
|
212
|
+
terminalConnect: "Connect",
|
|
213
|
+
terminalReconnect: "Reconnect",
|
|
214
|
+
terminalStatusConnecting: "Connecting…",
|
|
215
|
+
terminalStatusRunning: "Connected",
|
|
216
|
+
terminalStatusExited: "Process exited ({code})",
|
|
217
|
+
terminalStatusDetached: "Detached (opened elsewhere)",
|
|
218
|
+
terminalNoShells: "No shells available",
|
|
219
|
+
terminalShellsFailed: "Could not list shells: {message}",
|
|
220
|
+
terminalLoading: "Loading…",
|
|
187
221
|
};
|
|
188
222
|
export const zh = {
|
|
189
223
|
cardTitle: "dsh-podman",
|
|
190
224
|
cardDescription: "管理工作区容器及其镜像。",
|
|
225
|
+
versionMismatchMajor: "此插件与 orchestrator 的主版本不同;请更新 dsh 镜像或 orchestrator 镜像,使两者一致。",
|
|
226
|
+
versionMismatchMinor: "此插件与 orchestrator 的版本不同但兼容;建议同时更新两个镜像。",
|
|
227
|
+
versionsTitle: "版本",
|
|
228
|
+
orchestrator: "dsh-podman-orchestrator",
|
|
229
|
+
versionUnknown: "未知",
|
|
230
|
+
dsh: "dsh",
|
|
231
|
+
copyVersions: "复制版本",
|
|
232
|
+
copied: "已复制",
|
|
233
|
+
copyFailed: "复制失败",
|
|
191
234
|
reload: "刷新此视图",
|
|
192
|
-
reloading: "刷新中…",
|
|
193
235
|
notice: "提示",
|
|
194
|
-
configTitle: "配置",
|
|
195
236
|
defaultImage: "默认镜像",
|
|
196
|
-
socketsRoot: "套接字根目录",
|
|
197
|
-
projectsRoot: "项目根目录",
|
|
198
237
|
defaultImageHint: "工作区没有自带镜像时使用的镜像。",
|
|
238
|
+
defaultEnvironment: "默认环境变量",
|
|
239
|
+
defaultEnvironmentHint: "容器创建时注入的环境变量。编辑容器自身的环境变量后重建该容器,即可修改或移除其中的某一项。",
|
|
240
|
+
gitIdentity: "Git 身份",
|
|
241
|
+
gitName: "姓名",
|
|
242
|
+
gitEmail: "邮箱",
|
|
243
|
+
gitIdentityHint: "为新容器填入 GIT_AUTHOR_NAME/EMAIL 与 GIT_COMMITTER_NAME/EMAIL,使容器内提交的提交者信息正确。",
|
|
244
|
+
applyDefaults: "应用默认环境变量",
|
|
245
|
+
confirmApplyDefaults: "为缺少默认环境变量的容器补上这些变量?匹配的运行中容器会被重建(其进程与守护进程会停止);已有值保持不变,已停止的容器不会被处理。",
|
|
246
|
+
clear: "清除",
|
|
199
247
|
save: "保存",
|
|
200
248
|
discard: "放弃",
|
|
201
249
|
workspacesTitle: "工作区",
|
|
202
250
|
noContainers: "该工作区还没有容器。",
|
|
203
251
|
createContainer: "创建容器",
|
|
204
|
-
containersTitle: "容器",
|
|
205
252
|
containerName: "容器",
|
|
206
|
-
workspace: "工作区",
|
|
207
253
|
image: "镜像",
|
|
208
254
|
status: "状态",
|
|
209
255
|
created: "创建时间",
|
|
210
256
|
projects: "项目",
|
|
211
257
|
remove: "移除",
|
|
212
258
|
removePod: "移除 Pod",
|
|
213
|
-
confirmRemovePod: "
|
|
259
|
+
confirmRemovePod: "移除工作区“{workspace}”的 Pod 及其所有容器?卷和项目数据会保留。",
|
|
214
260
|
recreate: "重建",
|
|
215
261
|
recreateWithImage: "使用镜像重建",
|
|
216
262
|
imagesTitle: "镜像",
|
|
217
263
|
imageId: "镜像 ID",
|
|
218
|
-
baseImage: "基础镜像",
|
|
219
264
|
imageTag: "标签",
|
|
220
265
|
builtAt: "构建时间",
|
|
221
266
|
packages: "软件包",
|
|
@@ -263,15 +308,15 @@ export const zh = {
|
|
|
263
308
|
busy: "处理中…",
|
|
264
309
|
confirmTitle: "确认操作",
|
|
265
310
|
confirm: "确认",
|
|
266
|
-
confirmRemoveContainer: "
|
|
267
|
-
confirmRecreate: "
|
|
268
|
-
confirmRemoveImage: "
|
|
269
|
-
confirmRebuildImage: "
|
|
311
|
+
confirmRemoveContainer: "移除工作区“{workspace}”中的容器“{container}”?",
|
|
312
|
+
confirmRecreate: "重建工作区“{workspace}”中的容器“{container}”?其临时状态将丢失。",
|
|
313
|
+
confirmRemoveImage: "移除镜像“{image}”?使用它的容器需要用其他镜像重建。",
|
|
314
|
+
confirmRebuildImage: "就地重建镜像“{image}”?",
|
|
270
315
|
confirmRebuildAllImages: "按依赖顺序重建全部镜像(先基础镜像)?",
|
|
271
|
-
confirmRemoveVolume: "
|
|
272
|
-
confirmSetSecret: "
|
|
273
|
-
confirmRemoveSecret: "
|
|
274
|
-
confirmDetachSecret: "
|
|
316
|
+
confirmRemoveVolume: "移除卷“{volume}”及其数据?",
|
|
317
|
+
confirmSetSecret: "覆盖机密“{secret}”的值?",
|
|
318
|
+
confirmRemoveSecret: "移除机密“{secret}”?使用它的容器需先移除注入。",
|
|
319
|
+
confirmDetachSecret: "从环境变量 {env} 上移除机密“{secret}”?",
|
|
275
320
|
mountsTitle: "挂载",
|
|
276
321
|
addMount: "添加挂载",
|
|
277
322
|
mountKind: "类型",
|
|
@@ -301,14 +346,18 @@ export const zh = {
|
|
|
301
346
|
remountReject: "拒绝",
|
|
302
347
|
mountVolume: "卷",
|
|
303
348
|
mountSecret: "机密",
|
|
349
|
+
mountTmpfs: "tmpfs",
|
|
350
|
+
mountAt: "位于",
|
|
304
351
|
mountMode: "模式",
|
|
305
352
|
readOnly: "只读",
|
|
306
353
|
readWrite: "读写",
|
|
354
|
+
mountReadOnlySuffix: "(只读)",
|
|
355
|
+
mountReadWriteSuffix: "(读写)",
|
|
307
356
|
remountReadOnly: "重新挂载为只读",
|
|
308
357
|
remountReadWrite: "重新挂载为读写",
|
|
309
|
-
confirmRemountReadOnly: "
|
|
310
|
-
confirmRemountReadWrite: "
|
|
311
|
-
confirmRemoveMount: "
|
|
358
|
+
confirmRemountReadOnly: "将 {mount} 重新挂载为只读并重建容器?",
|
|
359
|
+
confirmRemountReadWrite: "将 {mount} 重新挂载为读写并重建容器?",
|
|
360
|
+
confirmRemoveMount: "从容器中移除挂载 {mount} 并重建容器?",
|
|
312
361
|
cachesTitle: "软件包缓存",
|
|
313
362
|
noCaches: "未配置软件包缓存。",
|
|
314
363
|
cacheUsage: "{size} · {n} 个文件",
|
|
@@ -323,6 +372,7 @@ export const zh = {
|
|
|
323
372
|
invalidImageId: "以字母、数字或 '_' 开头,仅可使用字母、数字、'.'、'_'、'-'、'/'、':'(最长 128 个字符)。",
|
|
324
373
|
terminalSignal: "信号 {signal}",
|
|
325
374
|
terminalExitCode: "退出码 {code}",
|
|
375
|
+
terminalNoExitCode: "无退出码",
|
|
326
376
|
terminalRunning: "运行中",
|
|
327
377
|
terminalFailed: "失败",
|
|
328
378
|
terminalDone: "已完成",
|
|
@@ -367,4 +417,22 @@ export const zh = {
|
|
|
367
417
|
toolTitle_daemon_logs: "守护进程日志",
|
|
368
418
|
toolTitle_daemon_restart: "重启守护进程",
|
|
369
419
|
toolTitle_daemon_stop: "停止守护进程",
|
|
420
|
+
terminalTabTitle: "终端",
|
|
421
|
+
terminalGuideTitle: "新建终端",
|
|
422
|
+
terminalGuideDescription: "在会话工作区运行命令",
|
|
423
|
+
terminalShortcut: "新建终端",
|
|
424
|
+
terminalShortcutNoSession: "请先选择会话",
|
|
425
|
+
terminalContainer: "容器",
|
|
426
|
+
terminalShell: "Shell",
|
|
427
|
+
terminalDefaultContainer: "默认容器",
|
|
428
|
+
terminalStart: "启动",
|
|
429
|
+
terminalConnect: "连接",
|
|
430
|
+
terminalReconnect: "重新连接",
|
|
431
|
+
terminalStatusConnecting: "正在连接…",
|
|
432
|
+
terminalStatusRunning: "已连接",
|
|
433
|
+
terminalStatusExited: "进程已退出({code})",
|
|
434
|
+
terminalStatusDetached: "已在其他位置打开",
|
|
435
|
+
terminalNoShells: "没有可用的 Shell",
|
|
436
|
+
terminalShellsFailed: "读取 Shell 失败:{message}",
|
|
437
|
+
terminalLoading: "正在加载…",
|
|
370
438
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { InjectFace, PropsLocale, PropsRuntime } from "@deepseek-ai/dsh-client-ui-slots";
|
|
2
|
+
import { type ReactNode } from "react";
|
|
3
|
+
import type { ContainerCardFace } from "./container-card-controller.js";
|
|
4
|
+
import { NS } from "./locales.js";
|
|
5
|
+
/** The card snapshot the guide reads; the tab's own actions open the terminal. */
|
|
6
|
+
export interface PodmanTerminalGuideInjected extends ContainerCardFace {
|
|
7
|
+
/** Owning session, used by the shells route and the injection contract. */
|
|
8
|
+
readonly sessionId: string;
|
|
9
|
+
}
|
|
10
|
+
export type PodmanTerminalGuideProps = PropsRuntime<"sidebar.right.tab.guide.entry"> & PropsLocale<typeof NS> & InjectFace<PodmanTerminalGuideInjected>;
|
|
11
|
+
export declare function PodmanTerminalGuide(props: PodmanTerminalGuideProps): ReactNode;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// SPDX-FileCopyrightText: 2026 Elouan Martinet <exa@elou.world>
|
|
3
|
+
//
|
|
4
|
+
// SPDX-License-Identifier: MIT
|
|
5
|
+
// The Podman terminal's guide card: pick a container and one of the shells that
|
|
6
|
+
// container really offers, then open a new terminal tab bound to that target in
|
|
7
|
+
// the Session's own workspace. It reads the same settings-card snapshot as the
|
|
8
|
+
// tab body and never asks for a workspace, because each Session has exactly one.
|
|
9
|
+
import { Button, PluginArtworkTerminal, } from "@deepseek-ai/dsh-client-ui-primitives";
|
|
10
|
+
import { useEffect, useState } from "react";
|
|
11
|
+
import { fieldLabel, fieldSelect, hint } from "./container-card-styles.js";
|
|
12
|
+
import { ContainerField } from "./podman-terminal.js";
|
|
13
|
+
import { PODMAN_TERMINAL_KIND } from "./terminal-tab.js";
|
|
14
|
+
import { readTerminalTarget, writeTerminalTarget, } from "./terminal-preference.js";
|
|
15
|
+
import { containerOptions, validContainer, validShell, } from "./terminal-targets.js";
|
|
16
|
+
import { fetchTerminalShells, fetchTerminalTarget, } from "./terminal-transport.js";
|
|
17
|
+
export function PodmanTerminalGuide(props) {
|
|
18
|
+
const { t, sessionId } = props;
|
|
19
|
+
const { tab } = props.useTabInfo();
|
|
20
|
+
const state = props.useContainerCard((snapshot) => snapshot);
|
|
21
|
+
// The host resolves the Session's workspace and reports it when it cannot.
|
|
22
|
+
const [target, setTarget] = useState({ phase: "loading" });
|
|
23
|
+
const workspace = target.phase === "ready"
|
|
24
|
+
? target.target.workspace
|
|
25
|
+
: undefined;
|
|
26
|
+
const workspaceSlug = target.phase === "ready"
|
|
27
|
+
? target.target.workspaceSlug
|
|
28
|
+
: undefined;
|
|
29
|
+
const unknownWorkspace = target.phase === "failed";
|
|
30
|
+
const [container, setContainer] = useState(undefined);
|
|
31
|
+
const [shells, setShells] = useState({ phase: "loading" });
|
|
32
|
+
const [shell, setShell] = useState(undefined);
|
|
33
|
+
// The last target this browser started from the card, reused below while it
|
|
34
|
+
// is still valid. Read once: the card shows it, it does not track it.
|
|
35
|
+
const [stored] = useState(() => readTerminalTarget());
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
props.reload();
|
|
38
|
+
}, [props.reload]);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const controller = new AbortController();
|
|
41
|
+
setTarget({ phase: "loading" });
|
|
42
|
+
void fetchTerminalTarget(sessionId, controller.signal).then((resolved) => {
|
|
43
|
+
if (!controller.signal.aborted) {
|
|
44
|
+
setTarget({ phase: "ready", target: resolved });
|
|
45
|
+
}
|
|
46
|
+
}, (error) => {
|
|
47
|
+
if (controller.signal.aborted)
|
|
48
|
+
return;
|
|
49
|
+
setTarget({
|
|
50
|
+
phase: "failed",
|
|
51
|
+
message: error instanceof Error ? error.message : String(error),
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
return () => {
|
|
55
|
+
controller.abort();
|
|
56
|
+
};
|
|
57
|
+
}, [sessionId]);
|
|
58
|
+
// The empty value means the workspace's default container; the workspace
|
|
59
|
+
// row's own containerName is that container's podman name, which the
|
|
60
|
+
// orchestrator rejects, so it is never used as a target. The choice waits for
|
|
61
|
+
// the first snapshot, otherwise the empty default would pre-empt a remembered
|
|
62
|
+
// named container before the options are known.
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (unknownWorkspace || workspace === undefined || container !== undefined) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (state.busy)
|
|
68
|
+
return;
|
|
69
|
+
setContainer(validContainer(stored?.container, containerOptions(state.containers, workspaceSlug)));
|
|
70
|
+
}, [
|
|
71
|
+
unknownWorkspace,
|
|
72
|
+
workspace,
|
|
73
|
+
container,
|
|
74
|
+
state.busy,
|
|
75
|
+
state.containers,
|
|
76
|
+
workspaceSlug,
|
|
77
|
+
stored,
|
|
78
|
+
]);
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (workspace === undefined || workspace === "" || container === undefined) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const controller = new AbortController();
|
|
84
|
+
setShells({ phase: "loading" });
|
|
85
|
+
void fetchTerminalShells(workspace, container, sessionId, controller.signal).then((list) => {
|
|
86
|
+
if (controller.signal.aborted)
|
|
87
|
+
return;
|
|
88
|
+
setShells({ phase: "ready", shells: list });
|
|
89
|
+
setShell((previous) => previous ?? validShell(stored?.shell, list) ?? list[0]?.path);
|
|
90
|
+
}, (error) => {
|
|
91
|
+
if (controller.signal.aborted)
|
|
92
|
+
return;
|
|
93
|
+
setShells({
|
|
94
|
+
phase: "failed",
|
|
95
|
+
message: error instanceof Error ? error.message : String(error),
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
return () => {
|
|
99
|
+
controller.abort();
|
|
100
|
+
};
|
|
101
|
+
}, [workspace, container, sessionId]);
|
|
102
|
+
const shellList = shells.phase === "ready" ? shells.shells : [];
|
|
103
|
+
const ready = !unknownWorkspace && container !== undefined &&
|
|
104
|
+
shell !== undefined &&
|
|
105
|
+
shellList.length > 0;
|
|
106
|
+
return (_jsxs("div", { style: CARD_STYLE, "data-sidebar-right-guide-entry": props.kind, children: [_jsxs("div", { style: HEADER_STYLE, children: [_jsx("span", { style: ICON_STYLE, "aria-hidden": "true", children: _jsx(PluginArtworkTerminal, { size: 22 }) }), _jsxs("span", { style: TEXT_STYLE, children: [_jsx("span", { style: TITLE_STYLE, children: props.title }), props.description === undefined
|
|
107
|
+
? null
|
|
108
|
+
: _jsx("span", { style: DESCRIPTION_STYLE, children: props.description })] })] }), state.workspaces.length === 0
|
|
109
|
+
? (_jsx("p", { style: hint, role: "status", children: state.busy ? t("terminalLoading") : t("unavailable") }))
|
|
110
|
+
: (_jsxs(_Fragment, { children: [target.phase === "failed" && (_jsx("p", { style: hint, role: "alert", children: target.message })), _jsxs("div", { style: FIELDS_STYLE, children: [_jsx(ContainerField, { containers: state.containers, workspaceSlug: workspaceSlug, container: container, disabled: unknownWorkspace, label: t("terminalContainer"), defaultLabel: t("terminalDefaultContainer"), selectStyle: fieldSelect, onContainer: (value) => {
|
|
111
|
+
// The new container may not offer the current shell, so the
|
|
112
|
+
// shells effect re-picks one (remembered when still valid).
|
|
113
|
+
setContainer(value);
|
|
114
|
+
setShell(undefined);
|
|
115
|
+
} }), _jsx("span", { style: fieldLabel, children: t("terminalShell") }), _jsx("select", { style: fieldSelect, "aria-label": t("terminalShell"), value: shell ?? "", disabled: unknownWorkspace || shells.phase !== "ready" ||
|
|
116
|
+
shellList.length === 0, onChange: (event) => {
|
|
117
|
+
setShell(event.target.value);
|
|
118
|
+
}, children: shellList.length === 0
|
|
119
|
+
? (_jsx("option", { value: "", children: unknownWorkspace
|
|
120
|
+
? ""
|
|
121
|
+
: shells.phase === "loading"
|
|
122
|
+
? t("terminalLoading")
|
|
123
|
+
: t("terminalNoShells") }))
|
|
124
|
+
: shellList.map((entry) => (_jsx("option", { value: entry.path, children: entry.name }, entry.path))) })] }), !unknownWorkspace && shells.phase === "failed" && (_jsx("p", { style: hint, role: "alert", children: t("terminalShellsFailed", { message: shells.message }) })), !unknownWorkspace && shells.phase === "loading" && (_jsx("p", { style: hint, role: "status", children: t("terminalLoading") })), !unknownWorkspace && shells.phase === "ready" &&
|
|
125
|
+
shellList.length === 0 && (_jsx("p", { style: hint, role: "status", children: t("terminalNoShells") })), _jsx("div", { style: ACTIONS_STYLE, children: _jsx(Button, { variant: "primary", size: "sm", disabled: !ready, onClick: () => {
|
|
126
|
+
if (container === undefined || shell === undefined)
|
|
127
|
+
return;
|
|
128
|
+
writeTerminalTarget({ container, shell });
|
|
129
|
+
// Replace the guide tab in place, exactly like the built-in
|
|
130
|
+
// guide cards, instead of adding a second terminal tab.
|
|
131
|
+
tab.actions.openTab(PODMAN_TERMINAL_KIND, {
|
|
132
|
+
replaceTab: true,
|
|
133
|
+
params: { container, shell },
|
|
134
|
+
});
|
|
135
|
+
}, children: t("terminalStart") }) })] }))] }));
|
|
136
|
+
}
|
|
137
|
+
// The card mirrors the harness guide capsule skin (`GuideBody .entry`): same
|
|
138
|
+
// padding, radius token, border and background as the entries beside it, so the
|
|
139
|
+
// glyph and title line up; the column layout and the internal gaps are ours
|
|
140
|
+
// because this card carries controls rather than being one clickable capsule.
|
|
141
|
+
const CARD_STYLE = {
|
|
142
|
+
display: "flex",
|
|
143
|
+
flexDirection: "column",
|
|
144
|
+
gap: "8px",
|
|
145
|
+
boxSizing: "border-box",
|
|
146
|
+
width: "100%",
|
|
147
|
+
padding: "14px 20px",
|
|
148
|
+
border: "0.5px solid var(--dsw-alias-border-l3)",
|
|
149
|
+
borderRadius: "var(--dsl-guide-entry-radius)",
|
|
150
|
+
background: "var(--dsw-alias-bg-layer-1)",
|
|
151
|
+
};
|
|
152
|
+
const HEADER_STYLE = {
|
|
153
|
+
display: "flex",
|
|
154
|
+
alignItems: "center",
|
|
155
|
+
gap: "14px",
|
|
156
|
+
minWidth: 0,
|
|
157
|
+
};
|
|
158
|
+
const ICON_STYLE = {
|
|
159
|
+
display: "flex",
|
|
160
|
+
flex: "none",
|
|
161
|
+
alignItems: "center",
|
|
162
|
+
justifyContent: "center",
|
|
163
|
+
width: "26px",
|
|
164
|
+
height: "26px",
|
|
165
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
166
|
+
};
|
|
167
|
+
const TEXT_STYLE = {
|
|
168
|
+
display: "flex",
|
|
169
|
+
flex: 1,
|
|
170
|
+
flexDirection: "column",
|
|
171
|
+
gap: "2px",
|
|
172
|
+
minWidth: 0,
|
|
173
|
+
};
|
|
174
|
+
const TITLE_STYLE = {
|
|
175
|
+
overflow: "hidden",
|
|
176
|
+
color: "var(--dsw-alias-label-primary)",
|
|
177
|
+
fontSize: "14px",
|
|
178
|
+
lineHeight: 1.4,
|
|
179
|
+
whiteSpace: "nowrap",
|
|
180
|
+
textOverflow: "ellipsis",
|
|
181
|
+
};
|
|
182
|
+
const DESCRIPTION_STYLE = {
|
|
183
|
+
overflow: "hidden",
|
|
184
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
185
|
+
fontSize: "11px",
|
|
186
|
+
lineHeight: 1.4,
|
|
187
|
+
whiteSpace: "nowrap",
|
|
188
|
+
textOverflow: "ellipsis",
|
|
189
|
+
};
|
|
190
|
+
// A centred label/select grid: each pair is one row, so a narrow card can never
|
|
191
|
+
// wrap a label away from its control. The auto column sizes to the widest label
|
|
192
|
+
// (right-aligned by `fieldLabel`), the second is capped at the select width so
|
|
193
|
+
// both controls line up, and the pair is centred in the card.
|
|
194
|
+
const FIELDS_STYLE = {
|
|
195
|
+
display: "grid",
|
|
196
|
+
gridTemplateColumns: "auto minmax(0, 160px)",
|
|
197
|
+
gap: "8px",
|
|
198
|
+
alignItems: "center",
|
|
199
|
+
justifyContent: "center",
|
|
200
|
+
width: "100%",
|
|
201
|
+
};
|
|
202
|
+
const ACTIONS_STYLE = {
|
|
203
|
+
display: "flex",
|
|
204
|
+
flexWrap: "wrap",
|
|
205
|
+
justifyContent: "center",
|
|
206
|
+
gap: "8px",
|
|
207
|
+
alignItems: "center",
|
|
208
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { InjectFace, PropsRuntime } from "@deepseek-ai/dsh-client-ui-slots";
|
|
2
|
+
import { type ReactNode } from "react";
|
|
3
|
+
/** Session identity the session-scope title registration injects. */
|
|
4
|
+
export interface PodmanTerminalTitleInjected {
|
|
5
|
+
readonly sessionId: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function PodmanTerminalTitle(props: PropsRuntime<"sidebar.right.pane.tab.title"> & InjectFace<PodmanTerminalTitleInjected>): ReactNode;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
import { shellName } from "./terminal-targets.js";
|
|
4
|
+
import { subscribeTerminalTitles, terminalTitle } from "./terminal-titles.js";
|
|
5
|
+
export function PodmanTerminalTitle(props) {
|
|
6
|
+
const { tab } = props.useTabInfo();
|
|
7
|
+
const params = tab.navigation.params;
|
|
8
|
+
// Only the session-scope identity is available here, so the store is keyed the
|
|
9
|
+
// same way the host retains a terminal.
|
|
10
|
+
const key = `${props.sessionId}:${tab.id}`;
|
|
11
|
+
const fallback = shellName(params?.shell) ?? tab.title;
|
|
12
|
+
const title = useSyncExternalStore(subscribeTerminalTitles, () => terminalTitle(key) ?? fallback);
|
|
13
|
+
return (_jsxs("span", { style: CHIP_STYLE, children: [_jsx(TerminalGlyph, {}), _jsx("span", { style: TITLE_STYLE, children: title })] }));
|
|
14
|
+
}
|
|
15
|
+
// The built-in tab chip's 16px terminal prompt, drawn in the surrounding ink
|
|
16
|
+
// instead of the plugin artwork's fixed brand palette.
|
|
17
|
+
function TerminalGlyph() {
|
|
18
|
+
return (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [_jsx("path", { d: "M3 4L7 8L3 12", stroke: "currentColor" }), _jsx("path", { d: "M9 12H13", stroke: "currentColor" })] }));
|
|
19
|
+
}
|
|
20
|
+
const CHIP_STYLE = {
|
|
21
|
+
display: "inline-flex",
|
|
22
|
+
alignItems: "center",
|
|
23
|
+
gap: "4px",
|
|
24
|
+
minWidth: 0,
|
|
25
|
+
};
|
|
26
|
+
const TITLE_STYLE = {
|
|
27
|
+
overflow: "hidden",
|
|
28
|
+
whiteSpace: "nowrap",
|
|
29
|
+
textOverflow: "ellipsis",
|
|
30
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { InjectFace, PropsLocale, PropsRuntime } from "@deepseek-ai/dsh-client-ui-slots";
|
|
2
|
+
import { type ReactNode } from "react";
|
|
3
|
+
import type { ContainerView } from "./card-protocol.js";
|
|
4
|
+
import type { ContainerCardFace } from "./container-card-controller.js";
|
|
5
|
+
import { NS } from "./locales.js";
|
|
6
|
+
/** Everything the tab body is given: framework shares plus the injected card face. */
|
|
7
|
+
export interface PodmanTerminalInjected extends ContainerCardFace {
|
|
8
|
+
/** Owning session, injected by the session-scope registration. */
|
|
9
|
+
readonly sessionId: string;
|
|
10
|
+
}
|
|
11
|
+
export type PodmanTerminalProps = PropsRuntime<"sidebar.right.pane.tab"> & PropsLocale<typeof NS> & InjectFace<PodmanTerminalInjected>;
|
|
12
|
+
/** The labelled container picker shared by the body and the guide card. */
|
|
13
|
+
interface ContainerFieldProps {
|
|
14
|
+
readonly containers: readonly ContainerView[];
|
|
15
|
+
readonly workspaceSlug: string | undefined;
|
|
16
|
+
readonly container: string | undefined;
|
|
17
|
+
readonly disabled: boolean;
|
|
18
|
+
readonly label: string;
|
|
19
|
+
readonly defaultLabel: string;
|
|
20
|
+
/** Select skin; stacked cards pass a full-width variant. */
|
|
21
|
+
readonly selectStyle?: React.CSSProperties;
|
|
22
|
+
readonly onContainer: (container: string) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare function ContainerField(props: ContainerFieldProps): ReactNode;
|
|
25
|
+
export declare function PodmanTerminal(props: PodmanTerminalProps): ReactNode;
|
|
26
|
+
export {};
|