@rakay-technology/kraft 0.7.5 → 0.7.7

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.
@@ -7,7 +7,7 @@ import {
7
7
  COMPONENT_INSTALLERS,
8
8
  checkAll,
9
9
  checkComponents
10
- } from "./chunk-TVURAFJ5.js";
10
+ } from "./chunk-MOSINQAM.js";
11
11
 
12
12
  // ../../packages/adapters/src/system/requirements.ts
13
13
  var REMOTE_SERVER_REQUIRED_COMPONENTS = ["docker", "git"];
@@ -19,7 +19,7 @@ import {
19
19
  rollbackEdgeTakeover,
20
20
  scanImportableSites,
21
21
  unreachableStaticRoots
22
- } from "./chunk-TVURAFJ5.js";
22
+ } from "./chunk-MOSINQAM.js";
23
23
  import {
24
24
  ourEdgeContainerRunning
25
25
  } from "./chunk-PCOTSRS4.js";
@@ -263,7 +263,7 @@ async function repairEdgeConflict(mode, apiPort, onLog) {
263
263
  }
264
264
  spawnSync("docker", ["restart", "kraft-edge"], { stdio: "ignore" });
265
265
  if (mode === "migrate" && scan.sites.length > 0) {
266
- const { importMigratedSites } = await import("./edge-import-YDPEIQDU.js");
266
+ const { importMigratedSites } = await import("./edge-import-RZD7MMOE.js");
267
267
  const outcome = await importMigratedSites(apiPort, scan.sites, certPems);
268
268
  if (outcome.registered.length === 0) {
269
269
  return {
@@ -2639,6 +2639,20 @@ async function installDocker(executor, onLog, config) {
2639
2639
  return { component: "docker", success: false, error: msg };
2640
2640
  }
2641
2641
  }
2642
+ function rhelRepoHint(profile, component, output) {
2643
+ if (profile.distroFamily !== "rhel") return "";
2644
+ if (!/no match for argument|unable to find a match|no package .* available/i.test(
2645
+ output
2646
+ ))
2647
+ return "";
2648
+ if (component === "fail2ban") {
2649
+ return ` On RHEL-family hosts, \`fail2ban\` lives in EPEL, which Kraft does not enable itself: install the \`epel-release\` package first, then retry this install.`;
2650
+ }
2651
+ if (component === "ufw") {
2652
+ return ` The \`ufw\` command is not packaged for RHEL-family hosts \u2014 \`firewalld\` is the native firewall and Kraft already drives it, so nothing needs installing.`;
2653
+ }
2654
+ return "";
2655
+ }
2642
2656
  async function installPackaged(executor, onLog, component, label, where) {
2643
2657
  const prep = await prepareExecutor(executor, component);
2644
2658
  if (!prep.ok) return prep.result;
@@ -2656,7 +2670,7 @@ async function installPackaged(executor, onLog, component, label, where) {
2656
2670
  onLog
2657
2671
  );
2658
2672
  if (code !== 0) {
2659
- const error = describeInstallFailure(label, code, output);
2673
+ const error = describeInstallFailure(label, code, output) + rhelRepoHint(prep.profile, component, output);
2660
2674
  onLog(log3(error, "error"));
2661
2675
  return { component, success: false, error };
2662
2676
  }
@@ -16,7 +16,7 @@ import {
16
16
  planAndApplyHostEdge,
17
17
  previewHostEdge,
18
18
  rollbackHostEdge
19
- } from "./chunk-4UITBYUK.js";
19
+ } from "./chunk-IGTODKUA.js";
20
20
  import {
21
21
  DEFAULT_REPO,
22
22
  PORTS_FILE,
@@ -43,7 +43,7 @@ import {
43
43
  resolvePorts,
44
44
  sourceBuildDir,
45
45
  verifyHostChannel
46
- } from "./chunk-TCB6MMZZ.js";
46
+ } from "./chunk-RU2BVUEV.js";
47
47
  import {
48
48
  startUnitHint,
49
49
  thisHost
@@ -87,7 +87,7 @@ import { dirname as dirname2, join as join6 } from "path";
87
87
  import { fileURLToPath } from "url";
88
88
 
89
89
  // src/lib/dashboard.ts
90
- import { spawnSync } from "child_process";
90
+ import { spawnSync as spawnSync2 } from "child_process";
91
91
  import { existsSync as existsSync2, mkdirSync as mkdirSync3, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
92
92
  import { join as join3 } from "path";
93
93
 
@@ -105,6 +105,7 @@ import {
105
105
  } from "fs";
106
106
  import { homedir } from "os";
107
107
  import { join } from "path";
108
+ import { spawnSync } from "child_process";
108
109
  var GITHUB_TOKEN_FILENAME = ".github-token";
109
110
  function githubTokenFile(dir = OS_DIR) {
110
111
  return join(dir, GITHUB_TOKEN_FILENAME);
@@ -195,6 +196,26 @@ function dockerHasAuthFor(host) {
195
196
  return false;
196
197
  }
197
198
  }
199
+ function dockerAvailable() {
200
+ try {
201
+ return spawnSync("docker", ["--version"], { stdio: "ignore" }).status === 0;
202
+ } catch {
203
+ return false;
204
+ }
205
+ }
206
+ function dockerLogin(host, username, token) {
207
+ try {
208
+ const r = spawnSync(
209
+ "docker",
210
+ ["login", host, "-u", username, "--password-stdin"],
211
+ { input: token, encoding: "utf8" }
212
+ );
213
+ const detail = `${r.stdout ?? ""}${r.stderr ?? ""}`.trim();
214
+ return { ok: r.status === 0, detail };
215
+ } catch (e) {
216
+ return { ok: false, detail: e.message };
217
+ }
218
+ }
198
219
 
199
220
  // src/lib/cache.ts
200
221
  var CACHE_DIR = join2(OS_DIR, "cache");
@@ -367,7 +388,7 @@ async function fetchBundle(tag, onProgress) {
367
388
  `Dashboard bundle checksum mismatch (expected ${expected}, got ${sha256}).`
368
389
  );
369
390
  }
370
- const untar = spawnSync("tar", ["-xzf", tarball, "-C", dir], {
391
+ const untar = spawnSync2("tar", ["-xzf", tarball, "-C", dir], {
371
392
  stdio: "inherit"
372
393
  });
373
394
  if (untar.status !== 0) {
@@ -387,7 +408,7 @@ async function fetchBundle(tag, onProgress) {
387
408
  }
388
409
 
389
410
  // src/lib/service.ts
390
- import { spawnSync as spawnSync2 } from "child_process";
411
+ import { spawnSync as spawnSync3 } from "child_process";
391
412
  import {
392
413
  existsSync as existsSync4,
393
414
  mkdirSync as mkdirSync5,
@@ -466,7 +487,7 @@ function runArgv(flags) {
466
487
  return [runtime, ...args, ...upArgs(flags)];
467
488
  }
468
489
  function run(cmd, args) {
469
- const r = spawnSync2(cmd, args, { encoding: "utf8" });
490
+ const r = spawnSync3(cmd, args, { encoding: "utf8" });
470
491
  return {
471
492
  ok: r.status === 0,
472
493
  out: `${r.stdout ?? ""}${r.stderr ?? ""}`.trim()
@@ -1921,7 +1942,7 @@ async function runForeground(opts, source) {
1921
1942
  const uiSpinner = ora("Preparing the dashboard\u2026").start();
1922
1943
  try {
1923
1944
  const bundle = await ensureDashboard({
1924
- tag: source ? "local" : opts.uiVersion || `v${"0.7.5"}`,
1945
+ tag: source ? "local" : opts.uiVersion || `v${"0.7.7"}`,
1925
1946
  onProgress: (received, total) => {
1926
1947
  if (total) {
1927
1948
  uiSpinner.text = `Downloading dashboard\u2026 ${Math.round(received / total * 100)}%`;
@@ -2038,6 +2059,7 @@ async function runForeground(opts, source) {
2038
2059
  }
2039
2060
 
2040
2061
  export {
2062
+ readStoredGithubToken,
2041
2063
  githubToken,
2042
2064
  githubTokenSource,
2043
2065
  storeGithubToken,
@@ -2046,6 +2068,8 @@ export {
2046
2068
  validateGithubToken,
2047
2069
  checkRepoReleases,
2048
2070
  dockerHasAuthFor,
2071
+ dockerAvailable,
2072
+ dockerLogin,
2049
2073
  CACHE_DIR,
2050
2074
  RELEASES_DIR,
2051
2075
  releaseDir,
@@ -16,7 +16,7 @@ import {
16
16
  } from "./chunk-5GPXMTE4.js";
17
17
  import {
18
18
  systemCatalog
19
- } from "./chunk-TVURAFJ5.js";
19
+ } from "./chunk-MOSINQAM.js";
20
20
  import {
21
21
  invalidateEdgeContainer,
22
22
  sanitizeEdgeVhosts
@@ -1776,7 +1776,7 @@ function operatorEnvPassthrough(managed, prev) {
1776
1776
  }
1777
1777
  var PRESERVED_ENV_HEADER = "# Preserved from your existing .env \u2014 set by you, not by `kraft up` (#485).";
1778
1778
  function resolveImageVersion(opts) {
1779
- return opts.version?.trim() || process.env.KRAFT_VERSION?.trim() || (true ? "0.7.5" : "latest");
1779
+ return opts.version?.trim() || process.env.KRAFT_VERSION?.trim() || (true ? "0.7.7" : "latest");
1780
1780
  }
1781
1781
  function managedEnvLines(opts, host, cfg, prev) {
1782
1782
  const lines = [
@@ -18,8 +18,8 @@ import "./chunk-DRK3MEDS.js";
18
18
  import "./chunk-3NQQXMDR.js";
19
19
  import "./chunk-RHLNVZMS.js";
20
20
  import "./chunk-MC4X55BW.js";
21
- import "./chunk-CO6FAYLO.js";
22
- import "./chunk-TVURAFJ5.js";
21
+ import "./chunk-HLF5PMKE.js";
22
+ import "./chunk-MOSINQAM.js";
23
23
  import "./chunk-VFPLICBX.js";
24
24
  import "./chunk-I3DPMTSF.js";
25
25
  import "./chunk-PCOTSRS4.js";
@@ -13,9 +13,9 @@ import {
13
13
  renderEdgeConflict,
14
14
  repairEdgeConflict,
15
15
  rollbackHostEdge
16
- } from "./chunk-4UITBYUK.js";
16
+ } from "./chunk-IGTODKUA.js";
17
17
  import "./chunk-5GPXMTE4.js";
18
- import "./chunk-TVURAFJ5.js";
18
+ import "./chunk-MOSINQAM.js";
19
19
  import "./chunk-VFPLICBX.js";
20
20
  import "./chunk-I3DPMTSF.js";
21
21
  import "./chunk-PCOTSRS4.js";
@@ -11,7 +11,7 @@ import {
11
11
  resolveEdgeImage,
12
12
  setDefaultEdgeImage,
13
13
  verifyEdgeServing
14
- } from "./chunk-TVURAFJ5.js";
14
+ } from "./chunk-MOSINQAM.js";
15
15
  import "./chunk-VFPLICBX.js";
16
16
  import "./chunk-I3DPMTSF.js";
17
17
  import "./chunk-PCOTSRS4.js";
@@ -5,7 +5,7 @@ const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  checkHostChannel,
7
7
  verifyHostChannel
8
- } from "./chunk-TCB6MMZZ.js";
8
+ } from "./chunk-RU2BVUEV.js";
9
9
  import "./chunk-2UQFOUSZ.js";
10
10
  import "./chunk-5GPXMTE4.js";
11
11
  import "./chunk-XZYFZ6A5.js";
@@ -17,8 +17,8 @@ import "./chunk-DRK3MEDS.js";
17
17
  import "./chunk-3NQQXMDR.js";
18
18
  import "./chunk-RHLNVZMS.js";
19
19
  import "./chunk-MC4X55BW.js";
20
- import "./chunk-CO6FAYLO.js";
21
- import "./chunk-TVURAFJ5.js";
20
+ import "./chunk-HLF5PMKE.js";
21
+ import "./chunk-MOSINQAM.js";
22
22
  import "./chunk-VFPLICBX.js";
23
23
  import "./chunk-I3DPMTSF.js";
24
24
  import "./chunk-PCOTSRS4.js";
package/dist/index.js CHANGED
@@ -8,7 +8,9 @@ import {
8
8
  assetUrl,
9
9
  checkRepoReleases,
10
10
  clearGithubToken,
11
+ dockerAvailable,
11
12
  dockerHasAuthFor,
13
+ dockerLogin,
12
14
  downloadToFile,
13
15
  ensureDashboard,
14
16
  expectedSha256,
@@ -23,6 +25,7 @@ import {
23
25
  normalizeUrl,
24
26
  parseSha256,
25
27
  readCliInstall,
28
+ readStoredGithubToken,
26
29
  releaseDir,
27
30
  releasesPage,
28
31
  resolveLatestTag,
@@ -35,7 +38,7 @@ import {
35
38
  upCommand,
36
39
  validateGithubToken,
37
40
  writeCliInstall
38
- } from "./chunk-TSDJJP6M.js";
41
+ } from "./chunk-OQ5TBV4T.js";
39
42
  import {
40
43
  bootstrapAdmin,
41
44
  detectPublicIp,
@@ -55,7 +58,7 @@ import {
55
58
  renderEdgeConflict,
56
59
  repairEdgeConflict,
57
60
  rollbackHostEdge
58
- } from "./chunk-4UITBYUK.js";
61
+ } from "./chunk-IGTODKUA.js";
59
62
  import {
60
63
  composeDown,
61
64
  composeInternalToken,
@@ -89,7 +92,7 @@ import {
89
92
  sourceBuildDir,
90
93
  storedApiPort,
91
94
  storedDashboardPort
92
- } from "./chunk-TCB6MMZZ.js";
95
+ } from "./chunk-RU2BVUEV.js";
93
96
  import {
94
97
  startUnitHint
95
98
  } from "./chunk-2UQFOUSZ.js";
@@ -107,11 +110,11 @@ import "./chunk-DRK3MEDS.js";
107
110
  import "./chunk-3NQQXMDR.js";
108
111
  import "./chunk-RHLNVZMS.js";
109
112
  import "./chunk-MC4X55BW.js";
110
- import "./chunk-CO6FAYLO.js";
113
+ import "./chunk-HLF5PMKE.js";
111
114
  import {
112
115
  detectInstalledProxy,
113
116
  scanImportableSites
114
- } from "./chunk-TVURAFJ5.js";
117
+ } from "./chunk-MOSINQAM.js";
115
118
  import "./chunk-VFPLICBX.js";
116
119
  import "./chunk-I3DPMTSF.js";
117
120
  import "./chunk-PCOTSRS4.js";
@@ -327,7 +330,7 @@ function getDashboardUrl(name) {
327
330
  }
328
331
 
329
332
  // src/lib/api-client.ts
330
- var USER_AGENT = `kraft-cli/${true ? "0.7.5" : "dev"}`;
333
+ var USER_AGENT = `kraft-cli/${true ? "0.7.7" : "dev"}`;
331
334
  function getApiUrl2() {
332
335
  return `${getApiUrl()}/api`;
333
336
  }
@@ -1226,7 +1229,7 @@ function looksCorrupted() {
1226
1229
  const err2 = lastServiceError();
1227
1230
  return !!err2 && CORRUPTION_RE.test(err2);
1228
1231
  }
1229
- function dockerAvailable() {
1232
+ function dockerAvailable2() {
1230
1233
  const r = spawnSync(
1231
1234
  "docker",
1232
1235
  ["version", "--format", "{{.Server.Version}}"],
@@ -1244,7 +1247,7 @@ function mapState(dockerState) {
1244
1247
  return "stopped";
1245
1248
  }
1246
1249
  function dockerServices() {
1247
- if (!dockerAvailable()) return [];
1250
+ if (!dockerAvailable2()) return [];
1248
1251
  const fmt = '{{.Names}} {{.State}} {{.Label "kraft.project"}}';
1249
1252
  const r = spawnSync(
1250
1253
  "docker",
@@ -1263,7 +1266,7 @@ function dockerServices() {
1263
1266
  });
1264
1267
  }
1265
1268
  function dockerNameRunning(nameFilter) {
1266
- if (!dockerAvailable()) return null;
1269
+ if (!dockerAvailable2()) return null;
1267
1270
  const r = spawnSync(
1268
1271
  "docker",
1269
1272
  ["ps", "--filter", `name=${nameFilter}`, "--format", "{{.Names}}"],
@@ -1273,7 +1276,7 @@ function dockerNameRunning(nameFilter) {
1273
1276
  return r.stdout.trim().length > 0;
1274
1277
  }
1275
1278
  async function hostControlCheck(api) {
1276
- const { checkHostChannel } = await import("./host-channel-preflight-625L6RNO.js");
1279
+ const { checkHostChannel } = await import("./host-channel-preflight-QMAF2BQW.js");
1277
1280
  return hostControlRow(await checkHostChannel().catch(() => null), api);
1278
1281
  }
1279
1282
  var NEVER_PROVISIONED_DETAIL = `never provisioned \u2014 run \`${HOST_CHANNEL_PROVISION_COMMAND}\``;
@@ -1832,7 +1835,7 @@ async function interactiveDoctor() {
1832
1835
  continue;
1833
1836
  }
1834
1837
  if (action2 === "host-control") {
1835
- const { verifyHostChannel } = await import("./host-channel-preflight-625L6RNO.js");
1838
+ const { verifyHostChannel } = await import("./host-channel-preflight-QMAF2BQW.js");
1836
1839
  const report3 = await verifyHostChannel().catch(() => null);
1837
1840
  if (report3?.status === "fixed")
1838
1841
  log2.success("Host control is reachable now.");
@@ -4224,7 +4227,7 @@ async function runRepair2(mode) {
4224
4227
  mode === "migrate" ? "Migrating the existing proxy's sites into the edge\u2026" : "Taking over :80/:443\u2026"
4225
4228
  );
4226
4229
  try {
4227
- const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-TT2777R5.js");
4230
+ const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-6YO27PPQ.js");
4228
4231
  sp?.stop();
4229
4232
  const res = await repairEdgeConflict2(mode, apiPort(), onLog);
4230
4233
  reportRepair(res);
@@ -4387,7 +4390,7 @@ async function panelRepair(mode) {
4387
4390
  mode === "migrate" ? "Migrating the existing proxy's sites\u2026" : "Taking over :80/:443\u2026"
4388
4391
  );
4389
4392
  try {
4390
- const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-TT2777R5.js");
4393
+ const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-6YO27PPQ.js");
4391
4394
  sp?.stop();
4392
4395
  const res = await repairEdgeConflict2(mode, apiPort(), onLog);
4393
4396
  renderRepair(res);
@@ -5492,7 +5495,7 @@ function printMonitoringNextSteps() {
5492
5495
  info(" kraft edge analytics -p <project> per-domain analytics");
5493
5496
  }
5494
5497
  async function runMonitoringInstall(opts) {
5495
- const up = await import("./up-G7ASYVWR.js");
5498
+ const up = await import("./up-IYR35YWW.js");
5496
5499
  let adminName = opts.adminName;
5497
5500
  let adminEmail = opts.adminEmail;
5498
5501
  let adminPassword = opts.adminPassword;
@@ -8066,7 +8069,7 @@ function applyOnlyArgv(selfArgs, json) {
8066
8069
  // src/commands/update.ts
8067
8070
  async function verifyHostChannelAfterUpdate() {
8068
8071
  if (isJsonMode()) return;
8069
- const { verifyHostChannel } = await import("./host-channel-preflight-625L6RNO.js");
8072
+ const { verifyHostChannel } = await import("./host-channel-preflight-QMAF2BQW.js");
8070
8073
  await verifyHostChannel().catch(() => {
8071
8074
  });
8072
8075
  }
@@ -8166,7 +8169,7 @@ async function runSourceUpdate(source, opts) {
8166
8169
  }
8167
8170
  var REINSTALL_HINT = "curl -fsSL https://get.kraft.io | sh";
8168
8171
  async function runTarballUpdate(install, opts) {
8169
- const current = "0.7.5";
8172
+ const current = "0.7.7";
8170
8173
  let latest;
8171
8174
  try {
8172
8175
  latest = (await resolveLatestTag()).replace(/^v/, "");
@@ -8287,7 +8290,7 @@ var updateCommand = new Command26("update").description("Update the Kraft CLI +
8287
8290
  const cliInstall = readCliInstall();
8288
8291
  if (cliInstall?.method === "tarball")
8289
8292
  return runTarballUpdate(cliInstall, opts);
8290
- const current = "0.7.5";
8293
+ const current = "0.7.7";
8291
8294
  let latest;
8292
8295
  try {
8293
8296
  latest = (await resolveLatestTag()).replace(/^v/, "");
@@ -8492,22 +8495,6 @@ function registryHost() {
8492
8495
  const raw = process.env.KRAFT_IMAGE_REGISTRY?.trim() || DEFAULT_IMAGE_REGISTRY;
8493
8496
  return raw.split("/")[0] || "ghcr.io";
8494
8497
  }
8495
- function dockerAvailable2() {
8496
- try {
8497
- return spawnSync8("docker", ["--version"], { stdio: "ignore" }).status === 0;
8498
- } catch {
8499
- return false;
8500
- }
8501
- }
8502
- function dockerLogin(host, username, token) {
8503
- const r = spawnSync8(
8504
- "docker",
8505
- ["login", host, "-u", username, "--password-stdin"],
8506
- { input: token, encoding: "utf8" }
8507
- );
8508
- const detail = `${r.stdout ?? ""}${r.stderr ?? ""}`.trim();
8509
- return { ok: r.status === 0, detail };
8510
- }
8511
8498
  function cancelled(v) {
8512
8499
  return typeof v === "symbol";
8513
8500
  }
@@ -8524,6 +8511,26 @@ async function runAuth(opts) {
8524
8511
  const repo = opts.repo?.trim() || githubRepo();
8525
8512
  const host = registryHost();
8526
8513
  let token = opts.token?.trim();
8514
+ let tokenReused = false;
8515
+ if (!token) {
8516
+ const stored = readStoredGithubToken();
8517
+ if (stored) {
8518
+ const prev = await validateGithubToken(stored);
8519
+ if (prev.valid) {
8520
+ token = stored;
8521
+ tokenReused = true;
8522
+ if (!isJsonMode())
8523
+ info(` Reusing stored token (${maskToken(stored)}).`);
8524
+ } else if (!process.stdin.isTTY) {
8525
+ err(
8526
+ "\n Stored token is no longer valid and there's no TTY to ask for a new one \u2014 re-run with `kraft gh auth --token <tok>`.\n"
8527
+ );
8528
+ process.exit(1);
8529
+ } else {
8530
+ info(" Stored token is no longer valid \u2014 let's replace it.\n");
8531
+ }
8532
+ }
8533
+ }
8527
8534
  if (!token) {
8528
8535
  if (!process.stdin.isTTY) {
8529
8536
  err(
@@ -8565,13 +8572,15 @@ async function runAuth(opts) {
8565
8572
  }
8566
8573
  storeGithubToken(token);
8567
8574
  if (!isJsonMode()) {
8568
- ok(` GitHub token stored (~/.kraft/.github-token, 0600).`);
8575
+ ok(
8576
+ tokenReused ? ` GitHub token still valid (${maskToken(token)}).` : ` GitHub token stored (~/.kraft/.github-token, 0600).`
8577
+ );
8569
8578
  if (releases.tag) info(` Latest release on ${repo}: ${releases.tag}`);
8570
8579
  }
8571
8580
  let docker = { loggedIn: false };
8572
8581
  if (opts.docker === false) {
8573
8582
  docker = { loggedIn: false, skipped: "opt-out (--no-docker)" };
8574
- } else if (!dockerAvailable2()) {
8583
+ } else if (!dockerAvailable()) {
8575
8584
  docker = { loggedIn: false, skipped: "no docker on PATH" };
8576
8585
  if (!isJsonMode()) info(" No docker on PATH \u2014 skipping registry login.");
8577
8586
  } else {
@@ -9128,7 +9137,7 @@ async function runWizard() {
9128
9137
  }
9129
9138
  }
9130
9139
  }
9131
- const uiTag = `v${"0.7.5"}`;
9140
+ const uiTag = `v${"0.7.7"}`;
9132
9141
  if (method === "bare") {
9133
9142
  const dl = spinner4();
9134
9143
  dl.start("Pulling the Kraft dist from GitHub");
@@ -9196,7 +9205,7 @@ async function runWizard() {
9196
9205
  const dashboardPort = String(ports.dashboard);
9197
9206
  const moved = portMoveNotice(ports, composeTrustedOriginUrls());
9198
9207
  if (moved.length) log5.info(moved.join("\n"));
9199
- if (!pinnedImagesReady({ version: "0.7.5" })) {
9208
+ if (!pinnedImagesReady({ version: "0.7.7" })) {
9200
9209
  cancel4(
9201
9210
  "The pinned Kraft image tag isn't in the registry yet \u2014 nothing on this box was changed."
9202
9211
  );
@@ -9218,6 +9227,27 @@ async function runWizard() {
9218
9227
  );
9219
9228
  process.exit(1);
9220
9229
  }
9230
+ const regHost = registryHost();
9231
+ if (!dockerHasAuthFor(regHost)) {
9232
+ const regToken = githubToken();
9233
+ if (regToken) {
9234
+ const username = ensure2(
9235
+ await text3({
9236
+ message: `GitHub username for the registry login (${regHost})`,
9237
+ placeholder: process.env.USER || "username",
9238
+ validate: (v) => v?.trim() ? void 0 : "A username is required."
9239
+ })
9240
+ );
9241
+ const logged = dockerLogin(regHost, username.trim(), regToken);
9242
+ if (logged.ok) {
9243
+ log5.info(`Registry login OK (${regHost} as ${username.trim()}).`);
9244
+ } else {
9245
+ log5.warn(
9246
+ `Registry login failed (${regHost}): ${logged.detail || "unknown error"} \u2014 the pull below will report it. Fix with \`kraft gh auth\`.`
9247
+ );
9248
+ }
9249
+ }
9250
+ }
9221
9251
  log5.step(
9222
9252
  sourceBuildDir() ? "Building the Kraft images before touching :80/:443 (first run takes a few minutes)\u2026" : "Pulling images before touching :80/:443\u2026"
9223
9253
  );
@@ -9226,7 +9256,7 @@ async function runWizard() {
9226
9256
  dashboardPort,
9227
9257
  publicUrl,
9228
9258
  trustProxy: behindProxy,
9229
- version: "0.7.5",
9259
+ version: "0.7.7",
9230
9260
  noHostControl: !allowHostControl
9231
9261
  });
9232
9262
  if (!fetched.ok) {
@@ -9257,7 +9287,7 @@ async function runWizard() {
9257
9287
  dashboardPort,
9258
9288
  publicUrl,
9259
9289
  trustProxy: behindProxy,
9260
- version: "0.7.5",
9290
+ version: "0.7.7",
9261
9291
  noHostControl: !allowHostControl
9262
9292
  });
9263
9293
  if (!up.ok) {
@@ -9349,7 +9379,7 @@ async function runWizard() {
9349
9379
  if (!result.domainRegistered)
9350
9380
  liveUrl2 = `http://localhost:${started.dashPort}`;
9351
9381
  for (const w of result.warnings) log5.warn(w);
9352
- const { verifyHostChannel } = await import("./host-channel-preflight-625L6RNO.js");
9382
+ const { verifyHostChannel } = await import("./host-channel-preflight-QMAF2BQW.js");
9353
9383
  await verifyHostChannel().catch(() => {
9354
9384
  });
9355
9385
  finishSetup({
@@ -9653,7 +9683,7 @@ function attachCompletion(program2) {
9653
9683
 
9654
9684
  // src/index.ts
9655
9685
  var program = new Command29();
9656
- program.name("kraft").description("Kraft CLI \u2014 install, run, and manage Kraft from your terminal").version("0.7.5").option("--json", "Machine-readable JSON output (stdout data only)").hook("preAction", (thisCommand) => {
9686
+ program.name("kraft").description("Kraft CLI \u2014 install, run, and manage Kraft from your terminal").version("0.7.7").option("--json", "Machine-readable JSON output (stdout data only)").hook("preAction", (thisCommand) => {
9657
9687
  if (thisCommand.opts().json) setJsonMode(true);
9658
9688
  }).action(async () => {
9659
9689
  const installed = serviceStatus().installed || readInstallMethod() === "compose";
@@ -1,11 +1,11 @@
1
1
  // src/node-bootstrap.ts
2
- import { spawnSync as spawnSync2 } from "child_process";
2
+ import { spawnSync as spawnSync3 } from "child_process";
3
3
  import { existsSync as existsSync3 } from "fs";
4
4
  import { join as join5 } from "path";
5
5
  import { createInterface } from "readline";
6
6
 
7
7
  // src/lib/node-runtime.ts
8
- import { execFileSync, spawnSync } from "child_process";
8
+ import { execFileSync, spawnSync as spawnSync2 } from "child_process";
9
9
  import {
10
10
  chmodSync,
11
11
  existsSync as existsSync2,
@@ -42,6 +42,7 @@ import {
42
42
  } from "fs";
43
43
  import { homedir as homedir2 } from "os";
44
44
  import { join as join2 } from "path";
45
+ import { spawnSync } from "child_process";
45
46
  var GITHUB_TOKEN_FILENAME = ".github-token";
46
47
  function githubTokenFile(dir = OS_DIR) {
47
48
  return join2(dir, GITHUB_TOKEN_FILENAME);
@@ -211,7 +212,7 @@ async function fetchVendoredNode(onLog) {
211
212
  }
212
213
  const unpacked = join4(RUNTIME_DIR, `node-${ver}-${os}-${arch}`);
213
214
  rmSync2(unpacked, { recursive: true, force: true });
214
- const untar = spawnSync("tar", ["-xzf", tarball, "-C", RUNTIME_DIR], {
215
+ const untar = spawnSync2("tar", ["-xzf", tarball, "-C", RUNTIME_DIR], {
215
216
  stdio: "inherit"
216
217
  });
217
218
  if (untar.status !== 0)
@@ -242,7 +243,7 @@ var NODE_REEXEC_ENV = "KRAFT_NODE_REEXEC";
242
243
  var VENDOR_ENV = "KRAFT_VENDOR_NODE";
243
244
  var vendoredNode = () => join5(OS_DIR, "runtime", "current", "bin", "node");
244
245
  function majorOf2(bin) {
245
- const out = spawnSync2(
246
+ const out = spawnSync3(
246
247
  bin,
247
248
  ["-e", "process.stdout.write(process.versions.node)"],
248
249
  {
@@ -253,7 +254,7 @@ function majorOf2(bin) {
253
254
  return Number.parseInt(out.stdout.trim().split(".")[0] ?? "", 10) || 0;
254
255
  }
255
256
  function reexec(nodeBin, cliPath) {
256
- const res = spawnSync2(nodeBin, [cliPath, ...process.argv.slice(2)], {
257
+ const res = spawnSync3(nodeBin, [cliPath, ...process.argv.slice(2)], {
257
258
  stdio: "inherit",
258
259
  env: { ...process.env, [NODE_REEXEC_ENV]: "1" }
259
260
  });
@@ -110595,6 +110595,19 @@ async function installDocker(executor, onLog, config2) {
110595
110595
  return { component: "docker", success: false, error: msg };
110596
110596
  }
110597
110597
  }
110598
+ function rhelRepoHint(profile, component, output) {
110599
+ if (profile.distroFamily !== "rhel")
110600
+ return "";
110601
+ if (!/no match for argument|unable to find a match|no package .* available/i.test(output))
110602
+ return "";
110603
+ if (component === "fail2ban") {
110604
+ return ` On RHEL-family hosts, \`fail2ban\` lives in EPEL, which Kraft does not` + ` enable itself: install the \`epel-release\` package first, then retry this install.`;
110605
+ }
110606
+ if (component === "ufw") {
110607
+ return ` The \`ufw\` command is not packaged for RHEL-family hosts — \`firewalld\`` + ` is the native firewall and Kraft already drives it, so nothing needs installing.`;
110608
+ }
110609
+ return "";
110610
+ }
110598
110611
  async function installPackaged(executor, onLog, component, label2, where) {
110599
110612
  const prep = await prepareExecutor(executor, component);
110600
110613
  if (!prep.ok)
@@ -110610,7 +110623,7 @@ async function installPackaged(executor, onLog, component, label2, where) {
110610
110623
  try {
110611
110624
  const { code, output } = await executor.streamExec(plan.value.installCommand, onLog);
110612
110625
  if (code !== 0) {
110613
- const error51 = describeInstallFailure(label2, code, output);
110626
+ const error51 = describeInstallFailure(label2, code, output) + rhelRepoHint(prep.profile, component, output);
110614
110627
  onLog(log3(error51, "error"));
110615
110628
  return { component, success: false, error: error51 };
110616
110629
  }
@@ -111649,6 +111662,28 @@ async function startEngine(executor, container, image, hostname3, onLog) {
111649
111662
  const run2 = await executor.streamExec(buildMailRunCommand(container, image, hostname3), onLog);
111650
111663
  return run2.code === 0;
111651
111664
  }
111665
+ async function startStoppedMailStack(executor, container, dbContainer, onLog) {
111666
+ const db = await containerState(executor, dbContainer).catch(() => null);
111667
+ if (db && !db.running) {
111668
+ onLog(log7("Starting the mail database (postgres sidecar)..."));
111669
+ const started = await executor.streamExec(`docker start ${sq2(dbContainer)}`, onLog).catch(() => ({ code: 1 }));
111670
+ if (started.code !== 0) {
111671
+ onLog(log7("Could not start the mail database container — the health check will report it.", "warn"));
111672
+ return;
111673
+ }
111674
+ const listening = await waitForPortListening(executor, MAIL_DB_PORT, {
111675
+ timeoutMs: 60000
111676
+ }).catch(() => null);
111677
+ if (listening && listening.checked && !listening.listening) {
111678
+ onLog(log7(`The mail database is not listening on :${MAIL_DB_PORT} after start.`, "warn"));
111679
+ }
111680
+ }
111681
+ const engine = await containerState(executor, container).catch(() => null);
111682
+ if (engine && !engine.running) {
111683
+ onLog(log7("Starting the mail engine container..."));
111684
+ await executor.streamExec(`docker start ${sq2(container)}`, onLog).catch(() => ({ code: 1 }));
111685
+ }
111686
+ }
111652
111687
  async function verifyMailEngine(executor, opts) {
111653
111688
  const timeoutMs = opts.verifyTimeoutMs ?? 180000;
111654
111689
  const smtp = await waitForPortListening(executor, 25, { timeoutMs });
@@ -111685,8 +111720,10 @@ async function ensureContainerMail(executor, opts) {
111685
111720
  const image = resolveMailImage(opts.image);
111686
111721
  const current = await containerImageRef(executor, container);
111687
111722
  if (current) {
111688
- if (current === image)
111723
+ if (current === image) {
111724
+ await startStoppedMailStack(executor, container, dbContainer, onLog);
111689
111725
  return { container, dbContainer, image, updated: false };
111726
+ }
111690
111727
  await handOverEnvFile(executor, ENGINE_ENV_FILE, onLog);
111691
111728
  const start2 = makeMailStart(executor, container, opts);
111692
111729
  const swap = await swapManagedImage(executor, {
@@ -272200,10 +272237,11 @@ async function stepDeployEngine(exec2, domain4, log11, config5) {
272200
272237
  if (health) {
272201
272238
  const down = health.filter((c2) => requiresMailComponent(c2.key) && c2.status !== "active");
272202
272239
  if (down.length > 0) {
272240
+ const describeDown = (c2) => `${c2.label} [${c2.status}${c2.subState ? `/${c2.subState}` : ""}${c2.detail ? `: ${c2.detail}` : ""}]`;
272203
272241
  return {
272204
272242
  stepId,
272205
272243
  success: false,
272206
- message: `Mail engine started but these components are not running: ${down.map((c2) => c2.label).join(", ")}.`
272244
+ message: `Mail engine started but these components are not running: ${down.map(describeDown).join(", ")}.`
272207
272245
  };
272208
272246
  }
272209
272247
  }
@@ -273236,7 +273274,7 @@ function validateDisplayName(name2) {
273236
273274
  async function listMailboxes(serverId, domain4) {
273237
273275
  validateDomain(domain4);
273238
273276
  return sshManager.withExecutor(serverId, async (exec2) => {
273239
- const rows = await queryRows(exec2, `SELECT${SELECT_COLUMNS} ${SELECT_FROM} WHERE domain = ${q3(domain4.toLowerCase())} ORDER BY mailbox.username`);
273277
+ const rows = await queryRows(exec2, `SELECT${SELECT_COLUMNS} ${SELECT_FROM} WHERE mailbox.domain = ${q3(domain4.toLowerCase())} ORDER BY mailbox.username`);
273240
273278
  const state = await readState(exec2);
273241
273279
  return rows.map((row) => annotatePlatformMailbox(row, state?.domain));
273242
273280
  });
@@ -273409,18 +273447,18 @@ async function hardDeleteMailbox(serverId, email6) {
273409
273447
  }
273410
273448
  var EMAIL_RE, LOCAL_PART_RE, SELECT_COLUMNS = `
273411
273449
  mailbox.username,
273412
- name,
273413
- domain,
273414
- quota AS "quotaMB",
273450
+ mailbox.name,
273451
+ mailbox.domain,
273452
+ mailbox.quota AS "quotaMB",
273415
273453
  uq.bytes AS "usedBytes",
273416
- storagebasedirectory,
273417
- storagenode,
273418
- maildir,
273419
- (active = 1) AS active,
273420
- (isadmin = 1) AS "isAdmin",
273421
- (isglobaladmin = 1) AS "isGlobalAdmin",
273422
- created::text AS "createdAt",
273423
- passwordlastchange::text AS "passwordLastChange"
273454
+ mailbox.storagebasedirectory,
273455
+ mailbox.storagenode,
273456
+ mailbox.maildir,
273457
+ (mailbox.active = 1) AS active,
273458
+ (mailbox.isadmin = 1) AS "isAdmin",
273459
+ (mailbox.isglobaladmin = 1) AS "isGlobalAdmin",
273460
+ mailbox.created::text AS "createdAt",
273461
+ mailbox.passwordlastchange::text AS "passwordLastChange"
273424
273462
  `, SELECT_FROM = `FROM mailbox LEFT JOIN used_quota AS uq ON uq.username = mailbox.username`, PlatformMailboxProtectedError, MailboxExistsError, MailboxNotFoundError;
273425
273463
  var init_mailboxes_service = __esm(async () => {
273426
273464
  init_src();
@@ -321467,7 +321505,7 @@ var package_default;
321467
321505
  var init_package = __esm(() => {
321468
321506
  package_default = {
321469
321507
  name: "@repo/api",
321470
- version: "0.7.5",
321508
+ version: "0.7.7",
321471
321509
  license: "Apache-2.0",
321472
321510
  private: true,
321473
321511
  type: "module",
@@ -4,8 +4,8 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  SystemManager
7
- } from "./chunk-CO6FAYLO.js";
8
- import "./chunk-TVURAFJ5.js";
7
+ } from "./chunk-HLF5PMKE.js";
8
+ import "./chunk-MOSINQAM.js";
9
9
  import "./chunk-VFPLICBX.js";
10
10
  import "./chunk-I3DPMTSF.js";
11
11
  import "./chunk-PCOTSRS4.js";
@@ -7,10 +7,10 @@ import {
7
7
  runHeadlessProvision,
8
8
  startService,
9
9
  upCommand
10
- } from "./chunk-TSDJJP6M.js";
10
+ } from "./chunk-OQ5TBV4T.js";
11
11
  import "./chunk-JK7KKBXI.js";
12
- import "./chunk-4UITBYUK.js";
13
- import "./chunk-TCB6MMZZ.js";
12
+ import "./chunk-IGTODKUA.js";
13
+ import "./chunk-RU2BVUEV.js";
14
14
  import "./chunk-2UQFOUSZ.js";
15
15
  import "./chunk-5GPXMTE4.js";
16
16
  import "./chunk-XZYFZ6A5.js";
@@ -22,8 +22,8 @@ import "./chunk-DRK3MEDS.js";
22
22
  import "./chunk-3NQQXMDR.js";
23
23
  import "./chunk-RHLNVZMS.js";
24
24
  import "./chunk-MC4X55BW.js";
25
- import "./chunk-CO6FAYLO.js";
26
- import "./chunk-TVURAFJ5.js";
25
+ import "./chunk-HLF5PMKE.js";
26
+ import "./chunk-MOSINQAM.js";
27
27
  import "./chunk-VFPLICBX.js";
28
28
  import "./chunk-I3DPMTSF.js";
29
29
  import "./chunk-PCOTSRS4.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rakay-technology/kraft",
3
- "version": "0.7.5",
3
+ "version": "0.7.7",
4
4
  "description": "Kraft CLI - deploy, manage, and open your Kraft platform from the terminal",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {