revdeck 0.2.0 → 0.2.1
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/CHANGELOG.md +9 -0
- package/README.md +11 -6
- package/README.ru.md +12 -6
- package/dist/cli.js +99 -38
- package/dist/cli.js.map +3 -3
- package/dist/daemon.js +50 -5
- package/dist/daemon.js.map +4 -4
- package/dist/mcp.js +1 -1
- package/dist/mcp.js.map +1 -1
- package/docs/adr/0001-daemon-first.md +3 -2
- package/docs/architecture.md +1 -0
- package/docs/integrations.md +10 -7
- package/docs/protocol.md +5 -2
- package/docs/ru/adr/0001-daemon-first.md +3 -2
- package/docs/ru/architecture.md +1 -0
- package/docs/ru/integrations.md +9 -7
- package/docs/ru/protocol.md +5 -2
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,15 @@ All notable changes to this project are documented here. The format is based on
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.1] - 2026-11-12
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- `revdeck devcontainer --write` no longer writes absolute host paths into the shared
|
|
14
|
+
`devcontainer.json`: mounts use `${localEnv:HOME}${localEnv:USERPROFILE}` and a stable
|
|
15
|
+
`~/.local/state/revdeck/devcontainer/{run,state}` bridge. The daemon listens on a second RPC socket
|
|
16
|
+
there for containers. Comments and formatting in an existing JSONC file are preserved.
|
|
17
|
+
|
|
9
18
|
## [0.2.0] - 2026-11-12
|
|
10
19
|
|
|
11
20
|
### Added
|
package/README.md
CHANGED
|
@@ -139,12 +139,17 @@ revdeck devcontainer # print the mounts and environment
|
|
|
139
139
|
revdeck devcontainer --write # merge them into .devcontainer/devcontainer.json
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
The command mounts the host
|
|
143
|
-
`/var/lib/revdeck` (read-only
|
|
144
|
-
`
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
The command mounts the stable host bridge `~/.local/state/revdeck/devcontainer/run` at `/run/revdeck`
|
|
143
|
+
(socket) and `~/.local/state/revdeck/devcontainer/state` at `/var/lib/revdeck` (read-only
|
|
144
|
+
`daemon.json`), and sets `REVDECK_RUNTIME_DIR`, `REVDECK_STATE_DIR`, `REVDECK_DEV_CONTAINER=1` and
|
|
145
|
+
`REVDECK_UI_HOST`. The JSON uses `${localEnv:HOME}${localEnv:USERPROFILE}` instead of an absolute
|
|
146
|
+
home path, so the same `.devcontainer/devcontainer.json` works for every developer. Comments and
|
|
147
|
+
foreign keys in an existing JSONC file are preserved.
|
|
148
|
+
|
|
149
|
+
The daemon creates the bridge socket on startup, so on the host run `revdeck daemon restart`, then
|
|
150
|
+
rebuild the container. Inside the container revdeck never starts a local daemon, so `gh`/`glab` are
|
|
151
|
+
never invoked there; if the host socket is missing it fails with a clear `DEVCONTAINER` error.
|
|
152
|
+
`revdeck doctor` is aware of this mode. For the UI from the container, start the host daemon with
|
|
148
153
|
`revdeck daemon start --host 0.0.0.0`.
|
|
149
154
|
|
|
150
155
|
## MCP
|
package/README.ru.md
CHANGED
|
@@ -125,12 +125,18 @@ revdeck devcontainer # показать mounts и окружение
|
|
|
125
125
|
revdeck devcontainer --write # добавить их в .devcontainer/devcontainer.json
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
Команда монтирует
|
|
129
|
-
(
|
|
130
|
-
`
|
|
131
|
-
В
|
|
132
|
-
|
|
133
|
-
|
|
128
|
+
Команда монтирует стабильный мост хоста `~/.local/state/revdeck/devcontainer/run` в `/run/revdeck`
|
|
129
|
+
(сокет) и `~/.local/state/revdeck/devcontainer/state` в `/var/lib/revdeck` (только чтение,
|
|
130
|
+
`daemon.json`) и выставляет `REVDECK_RUNTIME_DIR`, `REVDECK_STATE_DIR`, `REVDECK_DEV_CONTAINER=1` и
|
|
131
|
+
`REVDECK_UI_HOST`. В JSON пишется `${localEnv:HOME}${localEnv:USERPROFILE}`, а не абсолютный домашний
|
|
132
|
+
путь, поэтому один `.devcontainer/devcontainer.json` работает у всех разработчиков. Комментарии и
|
|
133
|
+
чужие ключи в существующем JSONC сохраняются.
|
|
134
|
+
|
|
135
|
+
Демон создаёт сокет моста при старте: на хосте выполните `revdeck daemon restart`, затем пересоберите
|
|
136
|
+
контейнер. В контейнере revdeck никогда не запускает свой демон, поэтому `gh`/`glab` там не
|
|
137
|
+
вызываются; если сокет хоста недоступен, команда падает с понятной ошибкой `DEVCONTAINER`.
|
|
138
|
+
`revdeck doctor` знает об этом режиме. Для UI из контейнера запустите демон на хосте с
|
|
139
|
+
`revdeck daemon start --host 0.0.0.0`.
|
|
134
140
|
|
|
135
141
|
## MCP
|
|
136
142
|
|
package/dist/cli.js
CHANGED
|
@@ -47,6 +47,19 @@ function socketPath() {
|
|
|
47
47
|
function daemonInfoPath() {
|
|
48
48
|
return path.join(stateDir(), "daemon.json");
|
|
49
49
|
}
|
|
50
|
+
function devcontainerBridgeDir() {
|
|
51
|
+
if (process.env.REVDECK_DEVCONTAINER_DIR) return path.resolve(process.env.REVDECK_DEVCONTAINER_DIR);
|
|
52
|
+
return path.join(os.homedir(), ".local", "state", "revdeck", "devcontainer");
|
|
53
|
+
}
|
|
54
|
+
function devcontainerRunDir() {
|
|
55
|
+
return path.join(devcontainerBridgeDir(), "run");
|
|
56
|
+
}
|
|
57
|
+
function devcontainerStateDir() {
|
|
58
|
+
return path.join(devcontainerBridgeDir(), "state");
|
|
59
|
+
}
|
|
60
|
+
function devcontainerSocketPath() {
|
|
61
|
+
return path.join(devcontainerRunDir(), "daemon.sock");
|
|
62
|
+
}
|
|
50
63
|
function logPath() {
|
|
51
64
|
return path.join(stateDir(), "daemon.log");
|
|
52
65
|
}
|
|
@@ -155,7 +168,7 @@ var VERSION;
|
|
|
155
168
|
var init_version = __esm({
|
|
156
169
|
"src/version.ts"() {
|
|
157
170
|
"use strict";
|
|
158
|
-
VERSION = "0.2.
|
|
171
|
+
VERSION = "0.2.1";
|
|
159
172
|
}
|
|
160
173
|
});
|
|
161
174
|
|
|
@@ -1967,22 +1980,26 @@ function isRecord(value) {
|
|
|
1967
1980
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1968
1981
|
}
|
|
1969
1982
|
|
|
1983
|
+
// src/cli/eject.ts
|
|
1984
|
+
import { applyEdits as applyEdits2, modify as modify2 } from "jsonc-parser";
|
|
1985
|
+
|
|
1970
1986
|
// src/cli/devcontainer.ts
|
|
1971
1987
|
init_paths();
|
|
1972
1988
|
import { existsSync as existsSync6 } from "node:fs";
|
|
1973
1989
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
|
|
1974
1990
|
import path6 from "node:path";
|
|
1991
|
+
import { applyEdits, modify, parse as parseJsonc2 } from "jsonc-parser";
|
|
1975
1992
|
init_locale();
|
|
1976
1993
|
init_format();
|
|
1977
1994
|
var CONTAINER_RUNTIME_DIR = "/run/revdeck";
|
|
1978
1995
|
var CONTAINER_STATE_DIR = "/var/lib/revdeck";
|
|
1979
1996
|
var CONTAINER_UI_HOST = "host.docker.internal";
|
|
1980
1997
|
function devcontainerPatch() {
|
|
1981
|
-
const
|
|
1998
|
+
const bridge = "${localEnv:HOME}${localEnv:USERPROFILE}/.local/state/revdeck/devcontainer";
|
|
1982
1999
|
return {
|
|
1983
2000
|
mounts: [
|
|
1984
|
-
{ type: "bind", source:
|
|
1985
|
-
{ type: "bind", source:
|
|
2001
|
+
{ type: "bind", source: `${bridge}/run`, target: CONTAINER_RUNTIME_DIR },
|
|
2002
|
+
{ type: "bind", source: `${bridge}/state`, target: CONTAINER_STATE_DIR, readonly: true }
|
|
1986
2003
|
],
|
|
1987
2004
|
containerEnv: {
|
|
1988
2005
|
REVDECK_RUNTIME_DIR: CONTAINER_RUNTIME_DIR,
|
|
@@ -2019,16 +2036,54 @@ function mergeDevcontainerConfig(existing, patch) {
|
|
|
2019
2036
|
result.runArgs = runArgs;
|
|
2020
2037
|
return result;
|
|
2021
2038
|
}
|
|
2039
|
+
function applyDevcontainerPatch(text, patch) {
|
|
2040
|
+
let current2 = text;
|
|
2041
|
+
const parsed = parseJsonc2(current2);
|
|
2042
|
+
if (!isRecord(parsed)) throw new Error("devcontainer.json: expected an object");
|
|
2043
|
+
const formatting = { formattingOptions: { insertSpaces: true, tabSize: 2 } };
|
|
2044
|
+
const mounts = Array.isArray(parsed.mounts) ? [...parsed.mounts] : [];
|
|
2045
|
+
for (const mount of patch.mounts) {
|
|
2046
|
+
const index = mounts.findIndex((item) => isRecord(item) && item.target === mount.target);
|
|
2047
|
+
const path10 = ["mounts", index >= 0 ? index : mounts.length];
|
|
2048
|
+
current2 = applyEdits(current2, modify(current2, path10, mount, formatting));
|
|
2049
|
+
if (index >= 0) mounts[index] = mount;
|
|
2050
|
+
else mounts.push(mount);
|
|
2051
|
+
}
|
|
2052
|
+
for (const [key, env] of [
|
|
2053
|
+
["containerEnv", patch.containerEnv],
|
|
2054
|
+
["remoteEnv", patch.remoteEnv]
|
|
2055
|
+
]) {
|
|
2056
|
+
for (const [name, value] of Object.entries(env)) {
|
|
2057
|
+
current2 = applyEdits(current2, modify(current2, [key, name], value, formatting));
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
const runArgs = Array.isArray(parsed.runArgs) ? parsed.runArgs.filter((item) => typeof item === "string") : [];
|
|
2061
|
+
for (const arg of patch.runArgs) {
|
|
2062
|
+
if (runArgs.includes(arg)) continue;
|
|
2063
|
+
current2 = applyEdits(current2, modify(current2, ["runArgs", runArgs.length], arg, formatting));
|
|
2064
|
+
runArgs.push(arg);
|
|
2065
|
+
}
|
|
2066
|
+
return current2.endsWith("\n") ? current2 : `${current2}
|
|
2067
|
+
`;
|
|
2068
|
+
}
|
|
2022
2069
|
async function runDevcontainer(rootInput, options) {
|
|
2023
2070
|
const root = findRepoRoot(rootInput);
|
|
2024
2071
|
const patch = devcontainerPatch();
|
|
2025
|
-
await ensureDir(
|
|
2026
|
-
await ensureDir(
|
|
2072
|
+
await ensureDir(devcontainerRunDir());
|
|
2073
|
+
await ensureDir(devcontainerStateDir());
|
|
2027
2074
|
const dir = path6.join(root, ".devcontainer");
|
|
2028
2075
|
const file = path6.join(dir, "devcontainer.json");
|
|
2029
|
-
writers.out(tr("\
|
|
2030
|
-
writers.out(` ${tr("\u0441\u043E\u043A\u0435\u0442", "socket")}: ${
|
|
2031
|
-
writers.out(` ${tr("\u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435", "state")}: ${
|
|
2076
|
+
writers.out(tr("\u041C\u043E\u0441\u0442 revdeck \u0434\u043B\u044F \u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440\u0430:", "revdeck bridge for the container:"));
|
|
2077
|
+
writers.out(` ${tr("\u0441\u043E\u043A\u0435\u0442", "socket")}: ${devcontainerRunDir()} -> ${CONTAINER_RUNTIME_DIR}`);
|
|
2078
|
+
writers.out(` ${tr("\u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435", "state")}: ${devcontainerStateDir()} -> ${CONTAINER_STATE_DIR} (${tr("\u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0442\u0435\u043D\u0438\u0435", "read-only")})`);
|
|
2079
|
+
if (!existsSync6(devcontainerSocketPath())) {
|
|
2080
|
+
writers.err(
|
|
2081
|
+
tr(
|
|
2082
|
+
"! \u0441\u043E\u043A\u0435\u0442 \u043C\u043E\u0441\u0442\u0430 \u0435\u0449\u0451 \u043D\u0435 \u0441\u043E\u0437\u0434\u0430\u043D: \u043D\u0430 \u0445\u043E\u0441\u0442\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u0435 revdeck daemon restart",
|
|
2083
|
+
"! the bridge socket does not exist yet: run revdeck daemon restart on the host"
|
|
2084
|
+
)
|
|
2085
|
+
);
|
|
2086
|
+
}
|
|
2032
2087
|
writers.out(tr("\u0412 \u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440\u0435: \u0434\u0435\u043C\u043E\u043D, gh \u0438 glab \u043E\u0441\u0442\u0430\u044E\u0442\u0441\u044F \u043D\u0430 \u0445\u043E\u0441\u0442\u0435.", "In the container: the daemon, gh and glab stay on the host."));
|
|
2033
2088
|
if (!options.write) {
|
|
2034
2089
|
writers.out("");
|
|
@@ -2040,12 +2095,11 @@ async function runDevcontainer(rootInput, options) {
|
|
|
2040
2095
|
}
|
|
2041
2096
|
await mkdir3(dir, { recursive: true });
|
|
2042
2097
|
const existed = existsSync6(file);
|
|
2043
|
-
let
|
|
2098
|
+
let output;
|
|
2044
2099
|
if (existed) {
|
|
2045
2100
|
const text = await readFile4(file, "utf8");
|
|
2046
|
-
let parsed;
|
|
2047
2101
|
try {
|
|
2048
|
-
|
|
2102
|
+
output = applyDevcontainerPatch(text, patch);
|
|
2049
2103
|
} catch (error) {
|
|
2050
2104
|
throw new Error(
|
|
2051
2105
|
tr(
|
|
@@ -2054,22 +2108,18 @@ async function runDevcontainer(rootInput, options) {
|
|
|
2054
2108
|
)
|
|
2055
2109
|
);
|
|
2056
2110
|
}
|
|
2057
|
-
if (!isRecord(parsed)) throw new Error(`${path6.relative(root, file)}: ${tr("\u043E\u0436\u0438\u0434\u0430\u043B\u0441\u044F \u043E\u0431\u044A\u0435\u043A\u0442", "expected an object")}`);
|
|
2058
|
-
existing = parsed;
|
|
2059
2111
|
} else {
|
|
2060
|
-
existing = { image: "mcr.microsoft.com/devcontainers/base:bookworm" };
|
|
2112
|
+
const existing = { image: "mcr.microsoft.com/devcontainers/base:bookworm" };
|
|
2113
|
+
output = `${JSON.stringify(mergeDevcontainerConfig(existing, patch), null, 2)}
|
|
2114
|
+
`;
|
|
2061
2115
|
}
|
|
2062
|
-
|
|
2063
|
-
await writeFile2(file, `${JSON.stringify(merged, null, 2)}
|
|
2064
|
-
`);
|
|
2116
|
+
await writeFile2(file, output);
|
|
2065
2117
|
writers.out(`\u2714 ${path6.relative(root, file)}`);
|
|
2066
|
-
if (existed)
|
|
2067
|
-
writers.out(tr(" \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 \u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0435\u043C JSONC \u043D\u0435 \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u044E\u0442\u0441\u044F: \u043F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 diff.", " comments in an existing JSONC are not preserved: review the diff."));
|
|
2068
|
-
}
|
|
2118
|
+
if (existed) writers.out(tr(" \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u044B.", " comments were preserved."));
|
|
2069
2119
|
writers.out("");
|
|
2070
2120
|
writers.out(tr("\u0414\u0430\u043B\u044C\u0448\u0435:", "Next:"));
|
|
2071
|
-
writers.out(tr(" 1. \
|
|
2072
|
-
writers.out(tr(" 2. \
|
|
2121
|
+
writers.out(tr(" 1. \u041D\u0430 \u0445\u043E\u0441\u0442\u0435: revdeck daemon restart \u2014 \u043E\u043D \u0441\u043E\u0437\u0434\u0430\u0441\u0442 \u0441\u043E\u043A\u0435\u0442 \u043C\u043E\u0441\u0442\u0430.", " 1. On the host: revdeck daemon restart \u2014 it creates the bridge socket."));
|
|
2122
|
+
writers.out(tr(" 2. \u041F\u0435\u0440\u0435\u0441\u043E\u0431\u0435\u0440\u0438\u0442\u0435/\u043F\u0435\u0440\u0435\u043E\u0442\u043A\u0440\u043E\u0439\u0442\u0435 devcontainer.", " 2. Rebuild/reopen the devcontainer."));
|
|
2073
2123
|
writers.out(tr(" 3. \u0412 \u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440\u0435: revdeck doctor \u2014 \u043E\u043D \u043D\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043A\u0430\u0442\u044C glab/gh \u0432\u043D\u0443\u0442\u0440\u0438.", " 3. In the container: revdeck doctor \u2014 it will not look for glab/gh inside."));
|
|
2074
2124
|
writers.out(tr(" \u0414\u043B\u044F UI \u0438\u0437 \u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440\u0430 \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0435 \u0434\u0435\u043C\u043E\u043D \u043D\u0430 \u0445\u043E\u0441\u0442\u0435 \u0441 --host 0.0.0.0.", " For the UI from the container, start the daemon on the host with --host 0.0.0.0."));
|
|
2075
2125
|
}
|
|
@@ -2147,37 +2197,39 @@ async function runEject(rootInput, options) {
|
|
|
2147
2197
|
try {
|
|
2148
2198
|
const parsed = parseJsonc(text);
|
|
2149
2199
|
if (isRecord(parsed)) {
|
|
2150
|
-
const
|
|
2200
|
+
const formatting = { formattingOptions: { insertSpaces: true, tabSize: 2 } };
|
|
2201
|
+
let current2 = text;
|
|
2151
2202
|
let changed = false;
|
|
2152
|
-
if (Array.isArray(
|
|
2153
|
-
const mounts =
|
|
2154
|
-
if (mounts.length !==
|
|
2155
|
-
|
|
2203
|
+
if (Array.isArray(parsed.mounts)) {
|
|
2204
|
+
const mounts = parsed.mounts.filter((item) => !(isRecord(item) && (item.target === CONTAINER_RUNTIME_DIR || item.target === CONTAINER_STATE_DIR)));
|
|
2205
|
+
if (mounts.length !== parsed.mounts.length) {
|
|
2206
|
+
current2 = applyEdits2(current2, modify2(current2, ["mounts"], mounts, formatting));
|
|
2156
2207
|
changed = true;
|
|
2157
2208
|
}
|
|
2158
2209
|
}
|
|
2159
2210
|
for (const key of ["containerEnv", "remoteEnv"]) {
|
|
2160
|
-
if (!isRecord(
|
|
2161
|
-
const env = { ...
|
|
2211
|
+
if (!isRecord(parsed[key])) continue;
|
|
2212
|
+
const env = { ...parsed[key] };
|
|
2162
2213
|
for (const name of ["REVDECK_RUNTIME_DIR", "REVDECK_STATE_DIR", "REVDECK_DEV_CONTAINER", "REVDECK_UI_HOST"]) delete env[name];
|
|
2163
|
-
if (Object.keys(env).length !== Object.keys(
|
|
2164
|
-
|
|
2214
|
+
if (Object.keys(env).length !== Object.keys(parsed[key]).length) {
|
|
2215
|
+
current2 = applyEdits2(current2, modify2(current2, [key], env, formatting));
|
|
2165
2216
|
changed = true;
|
|
2166
2217
|
}
|
|
2167
2218
|
}
|
|
2168
|
-
if (Array.isArray(
|
|
2169
|
-
const args =
|
|
2170
|
-
if (args.length !==
|
|
2171
|
-
|
|
2219
|
+
if (Array.isArray(parsed.runArgs)) {
|
|
2220
|
+
const args = parsed.runArgs.filter((item) => item !== "--add-host=host.docker.internal:host-gateway");
|
|
2221
|
+
if (args.length !== parsed.runArgs.length) {
|
|
2222
|
+
current2 = applyEdits2(current2, modify2(current2, ["runArgs"], args, formatting));
|
|
2172
2223
|
changed = true;
|
|
2173
2224
|
}
|
|
2174
2225
|
}
|
|
2175
2226
|
if (changed) {
|
|
2227
|
+
const output = current2.endsWith("\n") ? current2 : `${current2}
|
|
2228
|
+
`;
|
|
2176
2229
|
changes.push({
|
|
2177
2230
|
path: ".devcontainer/devcontainer.json",
|
|
2178
2231
|
action: tr("\u0443\u0431\u0440\u0430\u0442\u044C \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435 \u043A \u0434\u0435\u043C\u043E\u043D\u0443 \u0445\u043E\u0441\u0442\u0430", "remove the host daemon connection"),
|
|
2179
|
-
remove: () => writeFile3(devcontainer,
|
|
2180
|
-
`)
|
|
2232
|
+
remove: () => writeFile3(devcontainer, output)
|
|
2181
2233
|
});
|
|
2182
2234
|
}
|
|
2183
2235
|
}
|
|
@@ -2785,6 +2837,15 @@ function openBrowser(url) {
|
|
|
2785
2837
|
});
|
|
2786
2838
|
}
|
|
2787
2839
|
async function daemon(action, values = {}) {
|
|
2840
|
+
if (isDevContainer() && ["start", "stop", "restart", "install", "uninstall"].includes(action)) {
|
|
2841
|
+
fail(
|
|
2842
|
+
tr(
|
|
2843
|
+
"\u0432 devcontainer \u0434\u0435\u043C\u043E\u043D\u043E\u043C \u0443\u043F\u0440\u0430\u0432\u043B\u044F\u0435\u0442 \u0445\u043E\u0441\u0442: \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u0443 \u043D\u0430 \u0445\u043E\u0441\u0442\u0435",
|
|
2844
|
+
"the daemon is managed by the host in a devcontainer: run this command on the host"
|
|
2845
|
+
),
|
|
2846
|
+
tr("revdeck daemon restart \u043D\u0430 \u0445\u043E\u0441\u0442\u0435", "revdeck daemon restart on the host")
|
|
2847
|
+
);
|
|
2848
|
+
}
|
|
2788
2849
|
if (action === "start") {
|
|
2789
2850
|
const { client: client2, started } = await ensureDaemon({
|
|
2790
2851
|
...values.host ? { daemonArgs: ["--host", String(values.host)] } : {}
|