@rakay-technology/kraft 0.7.4 → 0.7.5

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.
Files changed (48) hide show
  1. package/README.md +1 -11
  2. package/dist/bare-JM3EX7S4.js +27 -0
  3. package/dist/{chunk-EW4PHKB2.js → chunk-2UQFOUSZ.js} +8 -8
  4. package/dist/{chunk-WYNM7L22.js → chunk-2Y62WP2D.js} +2 -2
  5. package/dist/{chunk-N4OALTFK.js → chunk-3RCXJZJD.js} +1 -1
  6. package/dist/{chunk-PZVKPCKE.js → chunk-4UITBYUK.js} +5 -5
  7. package/dist/{chunk-DM3PKWDC.js → chunk-7UKBMDUF.js} +9 -9
  8. package/dist/{chunk-MNV2QFHW.js → chunk-BN23UUSF.js} +1 -1
  9. package/dist/{chunk-I2TOOF2A.js → chunk-CO6FAYLO.js} +1 -1
  10. package/dist/{chunk-AJ4QZLZ2.js → chunk-DFVWR6JM.js} +2 -2
  11. package/dist/{chunk-S3QBGGVP.js → chunk-DI54Y66N.js} +3 -3
  12. package/dist/{chunk-HMJUFZK7.js → chunk-DJNKEVZ7.js} +1 -1
  13. package/dist/{chunk-XVKUFMIB.js → chunk-HFOE2IXZ.js} +1 -1
  14. package/dist/{chunk-RFOBMHQ7.js → chunk-JK7KKBXI.js} +4 -4
  15. package/dist/{chunk-XGCG4MD5.js → chunk-K24SBFI2.js} +1 -1
  16. package/dist/{chunk-TAML5WMA.js → chunk-MC4X55BW.js} +3 -3
  17. package/dist/chunk-ND23EK7Y.js +81645 -0
  18. package/dist/{chunk-YZUKHG3S.js → chunk-PCOTSRS4.js} +3 -3
  19. package/dist/{chunk-MOLPYPVH.js → chunk-SPKRI7MF.js} +6 -6
  20. package/dist/{chunk-JSCZT76F.js → chunk-TCB6MMZZ.js} +10 -8
  21. package/dist/{chunk-PNNXWA2A.js → chunk-TSDJJP6M.js} +227 -100
  22. package/dist/{chunk-THTEUDBC.js → chunk-TVURAFJ5.js} +13 -13
  23. package/dist/{chunk-Y7PVJUXJ.js → chunk-VFPLICBX.js} +6 -6
  24. package/dist/{chunk-BQMFIXHI.js → chunk-XBGSR22I.js} +5 -5
  25. package/dist/{chunk-OFXBNFNL.js → chunk-YY5DEAZI.js} +2 -2
  26. package/dist/{chunk-PNRPKRJU.js → chunk-ZNVAHQRY.js} +6 -6
  27. package/dist/{chunk-YRSZPVMB.js → chunk-ZQJU5CTZ.js} +1 -1
  28. package/dist/{detect-676SNZK4.js → detect-N4HFQZ6Y.js} +4 -4
  29. package/dist/{docker-GOT3Q7DJ.js → docker-DU7JA2AK.js} +8 -8
  30. package/dist/{docker-edge-executor-VO6JHHW2.js → docker-edge-executor-MPIPQHNF.js} +7 -7
  31. package/dist/{edge-import-NFCHIW7G.js → edge-import-YDPEIQDU.js} +22 -22
  32. package/dist/{edge-preflight-QUJ757C6.js → edge-preflight-TT2777R5.js} +13 -13
  33. package/dist/{ensure-container-edge-Q7IZXHGM.js → ensure-container-edge-T5WRCJSE.js} +11 -11
  34. package/dist/{executor-GKXKN52K.js → executor-ZWF2J7GS.js} +6 -6
  35. package/dist/{host-channel-preflight-Z6HYSPKO.js → host-channel-preflight-625L6RNO.js} +22 -22
  36. package/dist/index.js +310 -86
  37. package/dist/{local-executor-OMMDKXCM.js → local-executor-W3O5HDLM.js} +3 -3
  38. package/dist/{nginx-VITTWZZU.js → nginx-XLDZIG4E.js} +9 -9
  39. package/dist/node-bootstrap.js +66 -32
  40. package/dist/{openresty-lua-6I3Z6PEQ.js → openresty-lua-ZNE6IBYU.js} +7 -7
  41. package/dist/{privilege-UQAI2HV4.js → privilege-IMARWVU2.js} +5 -5
  42. package/dist/server/index.js +58785 -770
  43. package/dist/{setup-JWKZIECM.js → setup-I3MTOIPW.js} +12 -12
  44. package/dist/{ssh-client-NWQVRCV7.js → ssh-client-LOCZTEUC.js} +2 -2
  45. package/dist/{up-P5DMQ5YO.js → up-G7ASYVWR.js} +25 -25
  46. package/package.json +1 -1
  47. package/dist/bare-HL2GUYE2.js +0 -27
  48. package/dist/chunk-PVOWHIND.js +0 -26781
package/dist/index.js CHANGED
@@ -4,29 +4,38 @@ import { createRequire as __ospCreateRequire } from "node:module";
4
4
  const require = __ospCreateRequire(import.meta.url);
5
5
  import {
6
6
  CACHE_DIR,
7
- RELEASES,
8
7
  RELEASES_DIR,
9
8
  assetUrl,
9
+ checkRepoReleases,
10
+ clearGithubToken,
11
+ dockerHasAuthFor,
10
12
  downloadToFile,
11
13
  ensureDashboard,
12
14
  expectedSha256,
13
15
  fetchSidecar,
14
16
  formatBytes,
17
+ githubRepo,
18
+ githubToken,
19
+ githubTokenSource,
15
20
  hashFile,
16
21
  headlessProvision,
22
+ maskToken,
17
23
  normalizeUrl,
18
24
  parseSha256,
19
25
  readCliInstall,
20
26
  releaseDir,
27
+ releasesPage,
21
28
  resolveLatestTag,
22
29
  restart,
23
30
  selfInvocation,
24
31
  serviceStatus,
25
32
  startService,
26
33
  stop,
34
+ storeGithubToken,
27
35
  upCommand,
36
+ validateGithubToken,
28
37
  writeCliInstall
29
- } from "./chunk-PNNXWA2A.js";
38
+ } from "./chunk-TSDJJP6M.js";
30
39
  import {
31
40
  bootstrapAdmin,
32
41
  detectPublicIp,
@@ -36,7 +45,7 @@ import {
36
45
  internalTokenRejectedProblem,
37
46
  waitDashboard,
38
47
  waitHealthy
39
- } from "./chunk-RFOBMHQ7.js";
48
+ } from "./chunk-JK7KKBXI.js";
40
49
  import {
41
50
  completeHostEdge,
42
51
  confirmEdgeAction,
@@ -46,7 +55,7 @@ import {
46
55
  renderEdgeConflict,
47
56
  repairEdgeConflict,
48
57
  rollbackHostEdge
49
- } from "./chunk-PZVKPCKE.js";
58
+ } from "./chunk-4UITBYUK.js";
50
59
  import {
51
60
  composeDown,
52
61
  composeInternalToken,
@@ -80,10 +89,10 @@ import {
80
89
  sourceBuildDir,
81
90
  storedApiPort,
82
91
  storedDashboardPort
83
- } from "./chunk-JSCZT76F.js";
92
+ } from "./chunk-TCB6MMZZ.js";
84
93
  import {
85
94
  startUnitHint
86
- } from "./chunk-EW4PHKB2.js";
95
+ } from "./chunk-2UQFOUSZ.js";
87
96
  import {
88
97
  DATA_DIR,
89
98
  LOG_DIR,
@@ -97,36 +106,37 @@ import "./chunk-42WQABXM.js";
97
106
  import "./chunk-DRK3MEDS.js";
98
107
  import "./chunk-3NQQXMDR.js";
99
108
  import "./chunk-RHLNVZMS.js";
100
- import "./chunk-TAML5WMA.js";
101
- import "./chunk-I2TOOF2A.js";
109
+ import "./chunk-MC4X55BW.js";
110
+ import "./chunk-CO6FAYLO.js";
102
111
  import {
103
112
  detectInstalledProxy,
104
113
  scanImportableSites
105
- } from "./chunk-THTEUDBC.js";
106
- import "./chunk-Y7PVJUXJ.js";
114
+ } from "./chunk-TVURAFJ5.js";
115
+ import "./chunk-VFPLICBX.js";
107
116
  import "./chunk-I3DPMTSF.js";
108
- import "./chunk-YZUKHG3S.js";
117
+ import "./chunk-PCOTSRS4.js";
109
118
  import "./chunk-ONKEYSMY.js";
110
119
  import "./chunk-ZWLDLTJP.js";
111
- import "./chunk-PNRPKRJU.js";
112
- import "./chunk-DM3PKWDC.js";
113
- import "./chunk-AJ4QZLZ2.js";
114
- import "./chunk-MOLPYPVH.js";
120
+ import "./chunk-ZNVAHQRY.js";
121
+ import "./chunk-7UKBMDUF.js";
122
+ import "./chunk-DFVWR6JM.js";
123
+ import "./chunk-SPKRI7MF.js";
115
124
  import "./chunk-ZVFS4LUA.js";
116
- import "./chunk-XGCG4MD5.js";
117
- import "./chunk-HMJUFZK7.js";
125
+ import "./chunk-K24SBFI2.js";
126
+ import "./chunk-DJNKEVZ7.js";
118
127
  import {
119
128
  LocalExecutor
120
- } from "./chunk-XVKUFMIB.js";
121
- import "./chunk-S3QBGGVP.js";
122
- import "./chunk-BQMFIXHI.js";
123
- import "./chunk-WYNM7L22.js";
124
- import "./chunk-N4OALTFK.js";
125
- import "./chunk-YRSZPVMB.js";
126
- import "./chunk-OFXBNFNL.js";
129
+ } from "./chunk-HFOE2IXZ.js";
130
+ import "./chunk-DI54Y66N.js";
131
+ import "./chunk-XBGSR22I.js";
132
+ import "./chunk-2Y62WP2D.js";
133
+ import "./chunk-3RCXJZJD.js";
134
+ import "./chunk-ZQJU5CTZ.js";
135
+ import "./chunk-YY5DEAZI.js";
127
136
  import "./chunk-3CJLKL6E.js";
128
- import "./chunk-MNV2QFHW.js";
137
+ import "./chunk-BN23UUSF.js";
129
138
  import {
139
+ DEFAULT_IMAGE_REGISTRY,
130
140
  HOST_CHANNEL_AUTH_REJECTED_SHORT,
131
141
  HOST_CHANNEL_PROVISION_COMMAND,
132
142
  LOCAL_API_URL,
@@ -146,11 +156,11 @@ import {
146
156
  summarizeHostChannelCause,
147
157
  validateReleaseRepository,
148
158
  validateReleaseVersionUrl
149
- } from "./chunk-PVOWHIND.js";
159
+ } from "./chunk-ND23EK7Y.js";
150
160
  import "./chunk-PXKCZB2I.js";
151
161
 
152
162
  // src/index.ts
153
- import { Command as Command28 } from "commander";
163
+ import { Command as Command29 } from "commander";
154
164
 
155
165
  // src/lib/output.ts
156
166
  import chalk from "chalk";
@@ -317,7 +327,7 @@ function getDashboardUrl(name) {
317
327
  }
318
328
 
319
329
  // src/lib/api-client.ts
320
- var USER_AGENT = `kraft-cli/${true ? "0.7.4" : "dev"}`;
330
+ var USER_AGENT = `kraft-cli/${true ? "0.7.5" : "dev"}`;
321
331
  function getApiUrl2() {
322
332
  return `${getApiUrl()}/api`;
323
333
  }
@@ -842,8 +852,8 @@ var initCmd = new Command7("init").description("Scaffold an kraft.json in the cu
842
852
  }
843
853
  const hints = detectHints(dir);
844
854
  const scaffold = { $schema: SCHEMA_URL, ...hints };
845
- const text3 = JSON.stringify(scaffold, null, 2) + "\n";
846
- writeFileSync3(path2, text3);
855
+ const text4 = JSON.stringify(scaffold, null, 2) + "\n";
856
+ writeFileSync3(path2, text4);
847
857
  if (isJsonMode()) {
848
858
  printJson({ path: path2, config: scaffold });
849
859
  return;
@@ -1263,7 +1273,7 @@ function dockerNameRunning(nameFilter) {
1263
1273
  return r.stdout.trim().length > 0;
1264
1274
  }
1265
1275
  async function hostControlCheck(api) {
1266
- const { checkHostChannel } = await import("./host-channel-preflight-Z6HYSPKO.js");
1276
+ const { checkHostChannel } = await import("./host-channel-preflight-625L6RNO.js");
1267
1277
  return hostControlRow(await checkHostChannel().catch(() => null), api);
1268
1278
  }
1269
1279
  var NEVER_PROVISIONED_DETAIL = `never provisioned \u2014 run \`${HOST_CHANNEL_PROVISION_COMMAND}\``;
@@ -1822,7 +1832,7 @@ async function interactiveDoctor() {
1822
1832
  continue;
1823
1833
  }
1824
1834
  if (action2 === "host-control") {
1825
- const { verifyHostChannel } = await import("./host-channel-preflight-Z6HYSPKO.js");
1835
+ const { verifyHostChannel } = await import("./host-channel-preflight-625L6RNO.js");
1826
1836
  const report3 = await verifyHostChannel().catch(() => null);
1827
1837
  if (report3?.status === "fixed")
1828
1838
  log2.success("Host control is reachable now.");
@@ -3853,8 +3863,8 @@ serviceCommand.addCommand(execCmd);
3853
3863
  import { Command as Command16 } from "commander";
3854
3864
  import chalk12 from "chalk";
3855
3865
  import ora2 from "ora";
3856
- function spin(text3) {
3857
- return isJsonMode() ? null : ora2(text3).start();
3866
+ function spin(text4) {
3867
+ return isJsonMode() ? null : ora2(text4).start();
3858
3868
  }
3859
3869
  function fail2(e) {
3860
3870
  if (e instanceof ApiError) {
@@ -4106,8 +4116,8 @@ import {
4106
4116
  confirm as confirm5,
4107
4117
  log as log3
4108
4118
  } from "@clack/prompts";
4109
- function spin2(text3) {
4110
- return isJsonMode() ? null : ora3(text3).start();
4119
+ function spin2(text4) {
4120
+ return isJsonMode() ? null : ora3(text4).start();
4111
4121
  }
4112
4122
  function fail3(e) {
4113
4123
  if (e instanceof ApiError) {
@@ -4214,7 +4224,7 @@ async function runRepair2(mode) {
4214
4224
  mode === "migrate" ? "Migrating the existing proxy's sites into the edge\u2026" : "Taking over :80/:443\u2026"
4215
4225
  );
4216
4226
  try {
4217
- const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-QUJ757C6.js");
4227
+ const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-TT2777R5.js");
4218
4228
  sp?.stop();
4219
4229
  const res = await repairEdgeConflict2(mode, apiPort(), onLog);
4220
4230
  reportRepair(res);
@@ -4377,7 +4387,7 @@ async function panelRepair(mode) {
4377
4387
  mode === "migrate" ? "Migrating the existing proxy's sites\u2026" : "Taking over :80/:443\u2026"
4378
4388
  );
4379
4389
  try {
4380
- const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-QUJ757C6.js");
4390
+ const { repairEdgeConflict: repairEdgeConflict2 } = await import("./edge-preflight-TT2777R5.js");
4381
4391
  sp?.stop();
4382
4392
  const res = await repairEdgeConflict2(mode, apiPort(), onLog);
4383
4393
  renderRepair(res);
@@ -5482,7 +5492,7 @@ function printMonitoringNextSteps() {
5482
5492
  info(" kraft edge analytics -p <project> per-domain analytics");
5483
5493
  }
5484
5494
  async function runMonitoringInstall(opts) {
5485
- const up = await import("./up-P5DMQ5YO.js");
5495
+ const up = await import("./up-G7ASYVWR.js");
5486
5496
  let adminName = opts.adminName;
5487
5497
  let adminEmail = opts.adminEmail;
5488
5498
  let adminPassword = opts.adminPassword;
@@ -6022,8 +6032,8 @@ function report2(obj, human) {
6022
6032
  if (isJsonMode()) printJson(obj);
6023
6033
  else human();
6024
6034
  }
6025
- function spinner3(text3) {
6026
- return isJsonMode() ? null : ora5(text3).start();
6035
+ function spinner3(text4) {
6036
+ return isJsonMode() ? null : ora5(text4).start();
6027
6037
  }
6028
6038
  async function confirm6(message, yes) {
6029
6039
  if (yes) return true;
@@ -6145,20 +6155,20 @@ var upgradeToAuthCommand = new Command19("upgrade-to-auth").description("Promote
6145
6155
  await guarded(async () => {
6146
6156
  const name = opts.name;
6147
6157
  const email = opts.email;
6148
- let password3 = opts.password;
6149
- if (!password3) {
6158
+ let password4 = opts.password;
6159
+ if (!password4) {
6150
6160
  if (!process.stdin.isTTY || isJsonMode()) {
6151
6161
  err("\n --password is required in non-interactive mode.\n");
6152
6162
  process.exit(1);
6153
6163
  }
6154
- password3 = await promptHidden(" New password: ");
6164
+ password4 = await promptHidden(" New password: ");
6155
6165
  }
6156
6166
  const res = await apiRequest("/system/upgrade-to-auth", {
6157
6167
  method: "POST",
6158
6168
  body: JSON.stringify({
6159
6169
  name,
6160
6170
  email,
6161
- password: password3,
6171
+ password: password4,
6162
6172
  useOwnMailServer: opts.useOwnMailServer === true
6163
6173
  })
6164
6174
  });
@@ -6427,8 +6437,8 @@ function guard2(fn) {
6427
6437
  }
6428
6438
  };
6429
6439
  }
6430
- function spin3(text3) {
6431
- return isJsonMode() ? null : ora6(text3).start();
6440
+ function spin3(text4) {
6441
+ return isJsonMode() ? null : ora6(text4).start();
6432
6442
  }
6433
6443
  function safeParse4(data) {
6434
6444
  try {
@@ -6758,17 +6768,17 @@ postmasterCmd.addCommand(
6758
6768
  "New password (min 12 chars); prompted if omitted"
6759
6769
  ).action(
6760
6770
  guard2(async (serverId, opts) => {
6761
- let password3 = opts.password;
6762
- if (!password3) {
6771
+ let password4 = opts.password;
6772
+ if (!password4) {
6763
6773
  if (isJsonMode()) {
6764
6774
  err(" --password is required in JSON mode.");
6765
6775
  process.exit(1);
6766
6776
  }
6767
6777
  const rl = createInterface7({ input: input6, output: output6 });
6768
- password3 = (await rl.question(" New postmaster password (min 12 chars): ")).trim();
6778
+ password4 = (await rl.question(" New postmaster password (min 12 chars): ")).trim();
6769
6779
  rl.close();
6770
6780
  }
6771
- if (!password3 || password3.length < 12) {
6781
+ if (!password4 || password4.length < 12) {
6772
6782
  err(" Password must be at least 12 characters.");
6773
6783
  process.exit(1);
6774
6784
  }
@@ -6777,7 +6787,7 @@ postmasterCmd.addCommand(
6777
6787
  "/mail/credentials/postmaster",
6778
6788
  {
6779
6789
  method: "POST",
6780
- body: JSON.stringify({ serverId, password: password3 })
6790
+ body: JSON.stringify({ serverId, password: password4 })
6781
6791
  }
6782
6792
  );
6783
6793
  sp?.succeed("Postmaster password updated.");
@@ -7293,8 +7303,8 @@ import chalk17 from "chalk";
7293
7303
  // src/lib/cmd-helpers.ts
7294
7304
  import chalk16 from "chalk";
7295
7305
  import ora8 from "ora";
7296
- function spin4(text3) {
7297
- return isJsonMode() ? null : ora8(text3).start();
7306
+ function spin4(text4) {
7307
+ return isJsonMode() ? null : ora8(text4).start();
7298
7308
  }
7299
7309
  function fail4(e) {
7300
7310
  if (e instanceof ApiError) {
@@ -7449,10 +7459,10 @@ var apiCommand = new Command23("api").description(
7449
7459
  if (opts.data) init.body = opts.data;
7450
7460
  try {
7451
7461
  const res = await apiRaw(url, init);
7452
- const text3 = await res.text();
7453
- let body = text3;
7462
+ const text4 = await res.text();
7463
+ let body = text4;
7454
7464
  try {
7455
- body = JSON.parse(text3);
7465
+ body = JSON.parse(text4);
7456
7466
  } catch {
7457
7467
  }
7458
7468
  if (typeof body === "string") {
@@ -7667,7 +7677,7 @@ var installCommand = new Command25("install").description("Download and install
7667
7677
  err(e.message);
7668
7678
  process.exit(1);
7669
7679
  }
7670
- const spin5 = (text3) => isJsonMode() ? null : ora9(text3).start();
7680
+ const spin5 = (text4) => isJsonMode() ? null : ora9(text4).start();
7671
7681
  let tag;
7672
7682
  try {
7673
7683
  if (opts.version) {
@@ -7684,7 +7694,7 @@ var installCommand = new Command25("install").description("Download and install
7684
7694
  const dir = releaseDir(tag);
7685
7695
  const assetPath = join9(dir, asset.name);
7686
7696
  const sidecarPath = `${assetPath}.sha256`;
7687
- const assetUrl2 = `${RELEASES}/download/${tag}/${asset.name}`;
7697
+ const assetUrl2 = `${releasesPage()}/download/${tag}/${asset.name}`;
7688
7698
  const sidecarUrl = `${assetUrl2}.sha256`;
7689
7699
  let downloaded = false;
7690
7700
  let sha;
@@ -8056,7 +8066,7 @@ function applyOnlyArgv(selfArgs, json) {
8056
8066
  // src/commands/update.ts
8057
8067
  async function verifyHostChannelAfterUpdate() {
8058
8068
  if (isJsonMode()) return;
8059
- const { verifyHostChannel } = await import("./host-channel-preflight-Z6HYSPKO.js");
8069
+ const { verifyHostChannel } = await import("./host-channel-preflight-625L6RNO.js");
8060
8070
  await verifyHostChannel().catch(() => {
8061
8071
  });
8062
8072
  }
@@ -8156,7 +8166,7 @@ async function runSourceUpdate(source, opts) {
8156
8166
  }
8157
8167
  var REINSTALL_HINT = "curl -fsSL https://get.kraft.io | sh";
8158
8168
  async function runTarballUpdate(install, opts) {
8159
- const current = "0.7.4";
8169
+ const current = "0.7.5";
8160
8170
  let latest;
8161
8171
  try {
8162
8172
  latest = (await resolveLatestTag()).replace(/^v/, "");
@@ -8277,7 +8287,7 @@ var updateCommand = new Command26("update").description("Update the Kraft CLI +
8277
8287
  const cliInstall = readCliInstall();
8278
8288
  if (cliInstall?.method === "tarball")
8279
8289
  return runTarballUpdate(cliInstall, opts);
8280
- const current = "0.7.4";
8290
+ const current = "0.7.5";
8281
8291
  let latest;
8282
8292
  try {
8283
8293
  latest = (await resolveLatestTag()).replace(/^v/, "");
@@ -8474,6 +8484,216 @@ var cacheCommand = new Command27("cache").description("Manage the local download
8474
8484
  process.exit(1);
8475
8485
  }).addCommand(pathCmd).addCommand(listCmd6).addCommand(verifyCmd2).addCommand(cleanCmd);
8476
8486
 
8487
+ // src/commands/gh.ts
8488
+ import { Command as Command28 } from "commander";
8489
+ import { spawnSync as spawnSync8 } from "child_process";
8490
+ import { password as password2, select as select4, text as text2 } from "@clack/prompts";
8491
+ function registryHost() {
8492
+ const raw = process.env.KRAFT_IMAGE_REGISTRY?.trim() || DEFAULT_IMAGE_REGISTRY;
8493
+ return raw.split("/")[0] || "ghcr.io";
8494
+ }
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
+ function cancelled(v) {
8512
+ return typeof v === "symbol";
8513
+ }
8514
+ async function askToken() {
8515
+ const v = await password2({
8516
+ message: "GitHub token (fine-grained PAT: Contents:read + Packages:read)",
8517
+ mask: "\u2022",
8518
+ validate: (s) => s.trim() ? void 0 : "Paste a token first."
8519
+ });
8520
+ if (cancelled(v)) return null;
8521
+ return v.trim();
8522
+ }
8523
+ async function runAuth(opts) {
8524
+ const repo = opts.repo?.trim() || githubRepo();
8525
+ const host = registryHost();
8526
+ let token = opts.token?.trim();
8527
+ if (!token) {
8528
+ if (!process.stdin.isTTY) {
8529
+ err(
8530
+ "\n No --token and no TTY \u2014 re-run with `kraft gh auth --token <tok>`.\n"
8531
+ );
8532
+ process.exit(1);
8533
+ }
8534
+ info(` Releases repo: ${repo}`);
8535
+ info(
8536
+ " Create a token at https://github.com/settings/personal-access-tokens/new"
8537
+ );
8538
+ info(" (fine-grained, this repo only: Contents:read + Packages:read).\n");
8539
+ const asked = await askToken();
8540
+ if (asked === null) {
8541
+ err("\n Cancelled \u2014 nothing was stored.\n");
8542
+ process.exit(1);
8543
+ }
8544
+ token = asked;
8545
+ }
8546
+ if (!token) {
8547
+ err("\n No token provided.\n");
8548
+ process.exit(1);
8549
+ }
8550
+ const check = await validateGithubToken(token);
8551
+ if (!check.valid) {
8552
+ err(
8553
+ check.status === 0 ? "\n Couldn't reach api.github.com \u2014 check your network and re-run.\n" : `
8554
+ Token rejected by GitHub (HTTP ${check.status}). Check it isn't expired or revoked.
8555
+ `
8556
+ );
8557
+ process.exit(1);
8558
+ }
8559
+ const releases = await checkRepoReleases(token, repo);
8560
+ if (!releases.reachable && !isJsonMode()) {
8561
+ info(
8562
+ ` Note: ${repo}/releases/latest is not reachable with this token (HTTP ${releases.status}) \u2014 either no release is published yet or the token lacks Contents:read on that repo. Storing anyway; the install will report the definitive error.
8563
+ `
8564
+ );
8565
+ }
8566
+ storeGithubToken(token);
8567
+ if (!isJsonMode()) {
8568
+ ok(` GitHub token stored (~/.kraft/.github-token, 0600).`);
8569
+ if (releases.tag) info(` Latest release on ${repo}: ${releases.tag}`);
8570
+ }
8571
+ let docker = { loggedIn: false };
8572
+ if (opts.docker === false) {
8573
+ docker = { loggedIn: false, skipped: "opt-out (--no-docker)" };
8574
+ } else if (!dockerAvailable2()) {
8575
+ docker = { loggedIn: false, skipped: "no docker on PATH" };
8576
+ if (!isJsonMode()) info(" No docker on PATH \u2014 skipping registry login.");
8577
+ } else {
8578
+ let username = opts.dockerUser?.trim();
8579
+ if (!username && !process.stdin.isTTY) {
8580
+ docker = { loggedIn: false, skipped: "no --docker-user and no TTY" };
8581
+ } else {
8582
+ if (!username) {
8583
+ const asked = await text2({
8584
+ message: `GitHub username for the registry login (${host})`,
8585
+ placeholder: process.env.USER || "username",
8586
+ validate: (s) => s.trim() ? void 0 : "A username is required."
8587
+ });
8588
+ if (cancelled(asked)) {
8589
+ err("\n Cancelled \u2014 token is stored, registry login skipped.\n");
8590
+ if (isJsonMode()) printJson({ authenticated: true, repo });
8591
+ else ok(" Next: run `kraft`.");
8592
+ return;
8593
+ }
8594
+ username = asked.trim();
8595
+ }
8596
+ const res = dockerLogin(host, username, token);
8597
+ docker = { loggedIn: res.ok };
8598
+ if (res.ok) {
8599
+ if (!isJsonMode()) ok(` Registry login OK (${host} as ${username}).`);
8600
+ } else {
8601
+ err(
8602
+ `
8603
+ Registry login failed (${host}): ${res.detail || "unknown error"}`
8604
+ );
8605
+ info(" Token is stored \u2014 fix the login with:");
8606
+ info(
8607
+ ` echo $CR_PAT | docker login ${host} -u ${username} --password-stdin
8608
+ `
8609
+ );
8610
+ }
8611
+ }
8612
+ }
8613
+ if (isJsonMode()) {
8614
+ printJson({
8615
+ authenticated: true,
8616
+ repo,
8617
+ latestRelease: releases.tag,
8618
+ registry: host,
8619
+ docker
8620
+ });
8621
+ } else {
8622
+ ok(" Next: run `kraft`.");
8623
+ }
8624
+ }
8625
+ function runStatus2() {
8626
+ const token = githubToken();
8627
+ const source = githubTokenSource();
8628
+ const host = registryHost();
8629
+ const status = {
8630
+ repo: githubRepo(),
8631
+ token: token ? maskToken(token) : null,
8632
+ tokenSource: source,
8633
+ registry: host,
8634
+ registryLogin: dockerHasAuthFor(host)
8635
+ };
8636
+ if (isJsonMode()) {
8637
+ printJson(status);
8638
+ return;
8639
+ }
8640
+ if (!token) {
8641
+ info(" No GitHub token on this box. Run `kraft gh auth` to add one.");
8642
+ info(` Releases repo: ${status.repo} | registry: ${host}`);
8643
+ return;
8644
+ }
8645
+ ok(` GitHub token: ${status.token} (from ${source})`);
8646
+ info(` Releases repo: ${status.repo}`);
8647
+ info(
8648
+ status.registryLogin ? ` Registry login: present for ${host}` : ` Registry login: MISSING for ${host} \u2014 re-run \`kraft gh auth\` (or docker login).`
8649
+ );
8650
+ }
8651
+ async function runLogout(opts) {
8652
+ const host = registryHost();
8653
+ if (!opts.yes && process.stdin.isTTY && !isJsonMode()) {
8654
+ const v = await select4({
8655
+ message: "Forget the stored GitHub token (and registry login)?",
8656
+ options: [
8657
+ { value: "yes", label: "Yes, log out" },
8658
+ { value: "no", label: "Cancel" }
8659
+ ]
8660
+ });
8661
+ if (cancelled(v) || v !== "yes") {
8662
+ info(" Cancelled \u2014 token kept.");
8663
+ return;
8664
+ }
8665
+ }
8666
+ const removed = clearGithubToken();
8667
+ let dockerOut = "";
8668
+ try {
8669
+ const r = spawnSync8("docker", ["logout", host], { encoding: "utf8" });
8670
+ dockerOut = `${r.stdout ?? ""}${r.stderr ?? ""}`.trim();
8671
+ } catch {
8672
+ }
8673
+ if (isJsonMode()) {
8674
+ printJson({ loggedOut: true, tokenRemoved: removed, registry: host });
8675
+ return;
8676
+ }
8677
+ ok(
8678
+ removed ? " GitHub token forgotten." : " No stored token (env-provided tokens are untouched)."
8679
+ );
8680
+ if (dockerOut) info(` docker: ${dockerOut}`);
8681
+ }
8682
+ var ghCommand = new Command28("gh").description(
8683
+ "GitHub auth for private releases + registries (one-time setup)"
8684
+ );
8685
+ ghCommand.command("auth").description(
8686
+ "Save a GitHub token (prompted, masked) and log the registry in \u2014 then plain `kraft` works"
8687
+ ).option(
8688
+ "--token <token>",
8689
+ "Token for non-interactive use (env GITHUB_TOKEN also works)"
8690
+ ).option(
8691
+ "--repo <owner/repo>",
8692
+ "Releases repo (default: KRAFT_GITHUB_REPO or rakay-technology/kraft)"
8693
+ ).option("--docker-user <user>", "GitHub username for the registry login").option("--no-docker", "Skip the registry login, store the token only").action(runAuth);
8694
+ ghCommand.command("status").description("Show what GitHub / registry auth this box has").action(runStatus2);
8695
+ ghCommand.command("logout").description("Forget the stored token (and registry login)").option("--yes", "Skip the confirmation prompt").action(runLogout);
8696
+
8477
8697
  // src/commands/wizard.ts
8478
8698
  import chalk19 from "chalk";
8479
8699
  import open2 from "open";
@@ -8482,9 +8702,9 @@ import { join as join13 } from "path";
8482
8702
  import {
8483
8703
  intro as intro4,
8484
8704
  outro as outro4,
8485
- text as text2,
8486
- password as password2,
8487
- select as select4,
8705
+ text as text3,
8706
+ password as password3,
8707
+ select as select5,
8488
8708
  spinner as spinner4,
8489
8709
  note as note3,
8490
8710
  log as log5,
@@ -8500,13 +8720,13 @@ function ensure2(value) {
8500
8720
  }
8501
8721
  async function promptLocalAdmin() {
8502
8722
  const name = ensure2(
8503
- await text2({
8723
+ await text3({
8504
8724
  message: "Your name",
8505
8725
  validate: (v) => v?.trim() ? void 0 : "Required"
8506
8726
  })
8507
8727
  ).trim();
8508
8728
  const email = ensure2(
8509
- await text2({
8729
+ await text3({
8510
8730
  message: "Email",
8511
8731
  placeholder: "you@example.com",
8512
8732
  // Same rule the headless path enforces (isValidEmail) — an `@`-only check
@@ -8515,13 +8735,13 @@ async function promptLocalAdmin() {
8515
8735
  })
8516
8736
  ).trim().toLowerCase();
8517
8737
  const pw = ensure2(
8518
- await password2({
8738
+ await password3({
8519
8739
  message: "Password",
8520
8740
  validate: (v) => v && v.length >= 8 ? void 0 : "At least 8 characters"
8521
8741
  })
8522
8742
  );
8523
8743
  ensure2(
8524
- await password2({
8744
+ await password3({
8525
8745
  message: "Confirm password",
8526
8746
  validate: (v) => v === pw ? void 0 : "Passwords don't match"
8527
8747
  })
@@ -8712,7 +8932,7 @@ async function runWizard() {
8712
8932
  }
8713
8933
  sp.stop("Couldn't detect the public IP automatically.", 1);
8714
8934
  publicHost = ensure2(
8715
- await text2({
8935
+ await text3({
8716
8936
  message: "This server's public IP or hostname",
8717
8937
  placeholder: "203.0.113.10",
8718
8938
  validate: (v) => v?.trim() ? void 0 : "Required \u2014 the edge proxy routes traffic to this address"
@@ -8729,7 +8949,7 @@ async function runWizard() {
8729
8949
  planning: while (true) {
8730
8950
  if (stage === "reach") {
8731
8951
  const reach = ensure2(
8732
- await select4({
8952
+ await select5({
8733
8953
  message: "How should this instance be reachable?",
8734
8954
  // Default to public — most people setting up on a server/VPS want a
8735
8955
  // domain + HTTPS; localhost-only is the deliberate opt-out.
@@ -8760,7 +8980,7 @@ async function runWizard() {
8760
8980
  }
8761
8981
  if (stage === "type") {
8762
8982
  const domainType = ensure2(
8763
- await select4({
8983
+ await select5({
8764
8984
  message: "How do you want a domain + HTTPS?",
8765
8985
  initialValue: canManage ? "custom" : "byo",
8766
8986
  options: [
@@ -8789,7 +9009,7 @@ async function runWizard() {
8789
9009
  }
8790
9010
  if (stage === "custom") {
8791
9011
  const raw2 = ensure2(
8792
- await text2({
9012
+ await text3({
8793
9013
  message: "Your domain",
8794
9014
  placeholder: "ops.example.com",
8795
9015
  initialValue: customDomainInput || void 0,
@@ -8816,7 +9036,7 @@ async function runWizard() {
8816
9036
  "DNS"
8817
9037
  );
8818
9038
  const go2 = ensure2(
8819
- await select4({
9039
+ await select5({
8820
9040
  message: "A record added?",
8821
9041
  options: [
8822
9042
  {
@@ -8839,7 +9059,7 @@ async function runWizard() {
8839
9059
  break planning;
8840
9060
  }
8841
9061
  const raw = ensure2(
8842
- await text2({
9062
+ await text3({
8843
9063
  message: "Your domain (served behind your proxy)",
8844
9064
  placeholder: "ops.example.com",
8845
9065
  initialValue: byoDomainInput || void 0,
@@ -8863,7 +9083,7 @@ async function runWizard() {
8863
9083
  "Confirm"
8864
9084
  );
8865
9085
  const go = ensure2(
8866
- await select4({
9086
+ await select5({
8867
9087
  message: "Continue?",
8868
9088
  options: [
8869
9089
  { value: "go", label: "Continue" },
@@ -8908,7 +9128,7 @@ async function runWizard() {
8908
9128
  }
8909
9129
  }
8910
9130
  }
8911
- const uiTag = `v${"0.7.4"}`;
9131
+ const uiTag = `v${"0.7.5"}`;
8912
9132
  if (method === "bare") {
8913
9133
  const dl = spinner4();
8914
9134
  dl.start("Pulling the Kraft dist from GitHub");
@@ -8928,6 +9148,9 @@ async function runWizard() {
8928
9148
  log5.info(
8929
9149
  "Check your network / that this release published its dashboard asset, then re-run `kraft`."
8930
9150
  );
9151
+ log5.info(
9152
+ "Private repo? Run `kraft gh auth` once (stores a token + registry login), then re-run `kraft`."
9153
+ );
8931
9154
  process.exit(1);
8932
9155
  }
8933
9156
  }
@@ -8942,7 +9165,7 @@ async function runWizard() {
8942
9165
  let allowHostControl = true;
8943
9166
  if (method === "compose") {
8944
9167
  allowHostControl = ensure2(
8945
- await select4({
9168
+ await select5({
8946
9169
  message: "Let Kraft operate this machine's OS?",
8947
9170
  initialValue: "allow",
8948
9171
  options: [
@@ -8973,7 +9196,7 @@ async function runWizard() {
8973
9196
  const dashboardPort = String(ports.dashboard);
8974
9197
  const moved = portMoveNotice(ports, composeTrustedOriginUrls());
8975
9198
  if (moved.length) log5.info(moved.join("\n"));
8976
- if (!pinnedImagesReady({ version: "0.7.4" })) {
9199
+ if (!pinnedImagesReady({ version: "0.7.5" })) {
8977
9200
  cancel4(
8978
9201
  "The pinned Kraft image tag isn't in the registry yet \u2014 nothing on this box was changed."
8979
9202
  );
@@ -9003,7 +9226,7 @@ async function runWizard() {
9003
9226
  dashboardPort,
9004
9227
  publicUrl,
9005
9228
  trustProxy: behindProxy,
9006
- version: "0.7.4",
9229
+ version: "0.7.5",
9007
9230
  noHostControl: !allowHostControl
9008
9231
  });
9009
9232
  if (!fetched.ok) {
@@ -9034,7 +9257,7 @@ async function runWizard() {
9034
9257
  dashboardPort,
9035
9258
  publicUrl,
9036
9259
  trustProxy: behindProxy,
9037
- version: "0.7.4",
9260
+ version: "0.7.5",
9038
9261
  noHostControl: !allowHostControl
9039
9262
  });
9040
9263
  if (!up.ok) {
@@ -9126,7 +9349,7 @@ async function runWizard() {
9126
9349
  if (!result.domainRegistered)
9127
9350
  liveUrl2 = `http://localhost:${started.dashPort}`;
9128
9351
  for (const w of result.warnings) log5.warn(w);
9129
- const { verifyHostChannel } = await import("./host-channel-preflight-Z6HYSPKO.js");
9352
+ const { verifyHostChannel } = await import("./host-channel-preflight-625L6RNO.js");
9130
9353
  await verifyHostChannel().catch(() => {
9131
9354
  });
9132
9355
  finishSetup({
@@ -9274,7 +9497,7 @@ ${chalk19.dim("Dashboard".padEnd(11))}${dashUrl}
9274
9497
  );
9275
9498
  }
9276
9499
  const action2 = ensure2(
9277
- await select4({
9500
+ await select5({
9278
9501
  message: "What would you like to do?",
9279
9502
  options: [
9280
9503
  ...corrupted ? [
@@ -9397,7 +9620,7 @@ ${chalk19.dim("Dashboard".padEnd(11))}${dashUrl}
9397
9620
  }
9398
9621
  case "reset": {
9399
9622
  const pw = ensure2(
9400
- await password2({
9623
+ await password3({
9401
9624
  message: "New admin password",
9402
9625
  validate: (v) => v && v.length >= 8 ? void 0 : "At least 8 characters"
9403
9626
  })
@@ -9429,8 +9652,8 @@ function attachCompletion(program2) {
9429
9652
  }
9430
9653
 
9431
9654
  // src/index.ts
9432
- var program = new Command28();
9433
- program.name("kraft").description("Kraft CLI \u2014 install, run, and manage Kraft from your terminal").version("0.7.4").option("--json", "Machine-readable JSON output (stdout data only)").hook("preAction", (thisCommand) => {
9655
+ 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) => {
9434
9657
  if (thisCommand.opts().json) setJsonMode(true);
9435
9658
  }).action(async () => {
9436
9659
  const installed = serviceStatus().installed || readInstallMethod() === "compose";
@@ -9443,6 +9666,7 @@ program.addCommand(uninstallCommand);
9443
9666
  program.addCommand(installCommand);
9444
9667
  program.addCommand(updateCommand);
9445
9668
  program.addCommand(openCommand);
9669
+ program.addCommand(ghCommand);
9446
9670
  program.addCommand(loginCommand);
9447
9671
  program.addCommand(logoutCommand);
9448
9672
  program.addCommand(initCommand);