hatchkit 0.1.1 → 0.1.3
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/dist/completion.d.ts +2 -0
- package/dist/completion.d.ts.map +1 -0
- package/dist/completion.js +207 -0
- package/dist/completion.js.map +1 -0
- package/dist/config.d.ts +33 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +455 -117
- package/dist/config.js.map +1 -1
- package/dist/deploy/keys.d.ts +6 -2
- package/dist/deploy/keys.d.ts.map +1 -1
- package/dist/deploy/keys.js +16 -2
- package/dist/deploy/keys.js.map +1 -1
- package/dist/deploy/pages.d.ts +2 -0
- package/dist/deploy/pages.d.ts.map +1 -0
- package/dist/deploy/pages.js +537 -0
- package/dist/deploy/pages.js.map +1 -0
- package/dist/deploy/rename-domain.d.ts +55 -0
- package/dist/deploy/rename-domain.d.ts.map +1 -0
- package/dist/deploy/rename-domain.js +290 -0
- package/dist/deploy/rename-domain.js.map +1 -0
- package/dist/deploy/terraform.d.ts.map +1 -1
- package/dist/deploy/terraform.js +90 -0
- package/dist/deploy/terraform.js.map +1 -1
- package/dist/dns.d.ts +7 -0
- package/dist/dns.d.ts.map +1 -0
- package/dist/dns.js +124 -0
- package/dist/dns.js.map +1 -0
- package/dist/doctor.d.ts +13 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +368 -0
- package/dist/doctor.js.map +1 -0
- package/dist/explain.d.ts +4 -0
- package/dist/explain.d.ts.map +1 -0
- package/dist/explain.js +173 -0
- package/dist/explain.js.map +1 -0
- package/dist/index.js +504 -66
- package/dist/index.js.map +1 -1
- package/dist/provision/glitchtip.d.ts +3 -0
- package/dist/provision/glitchtip.d.ts.map +1 -1
- package/dist/provision/glitchtip.js +18 -0
- package/dist/provision/glitchtip.js.map +1 -1
- package/dist/provision/index.d.ts +26 -0
- package/dist/provision/index.d.ts.map +1 -1
- package/dist/provision/index.js +435 -60
- package/dist/provision/index.js.map +1 -1
- package/dist/provision/openpanel.d.ts +7 -0
- package/dist/provision/openpanel.d.ts.map +1 -1
- package/dist/provision/openpanel.js +113 -48
- package/dist/provision/openpanel.js.map +1 -1
- package/dist/provision/resend.d.ts +23 -1
- package/dist/provision/resend.d.ts.map +1 -1
- package/dist/provision/resend.js +62 -1
- package/dist/provision/resend.js.map +1 -1
- package/dist/provision/write-env.d.ts +31 -0
- package/dist/provision/write-env.d.ts.map +1 -0
- package/dist/provision/write-env.js +94 -0
- package/dist/provision/write-env.js.map +1 -0
- package/dist/scaffold/infra.d.ts.map +1 -1
- package/dist/scaffold/infra.js +18 -1
- package/dist/scaffold/infra.js.map +1 -1
- package/dist/status.d.ts +30 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +169 -0
- package/dist/status.js.map +1 -0
- package/dist/templates/addons/analytics/sentry.ts.hbs +6 -0
- package/dist/utils/cloudflare-api.d.ts +30 -0
- package/dist/utils/cloudflare-api.d.ts.map +1 -0
- package/dist/utils/cloudflare-api.js +85 -0
- package/dist/utils/cloudflare-api.js.map +1 -0
- package/dist/utils/coolify-api.d.ts +3 -1
- package/dist/utils/coolify-api.d.ts.map +1 -1
- package/dist/utils/coolify-api.js +38 -4
- package/dist/utils/coolify-api.js.map +1 -1
- package/dist/utils/inwx-api.d.ts +36 -0
- package/dist/utils/inwx-api.d.ts.map +1 -0
- package/dist/utils/inwx-api.js +105 -0
- package/dist/utils/inwx-api.js.map +1 -0
- package/dist/utils/secrets.d.ts +8 -1
- package/dist/utils/secrets.d.ts.map +1 -1
- package/dist/utils/secrets.js +8 -1
- package/dist/utils/secrets.js.map +1 -1
- package/package.json +2 -2
package/dist/doctor.js
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `hatchkit doctor` — health check for every configured provider.
|
|
3
|
+
*
|
|
4
|
+
* Runs the cheapest idempotent verification call that proves the stored
|
|
5
|
+
* credential still works (GET-only, no writes). Reports a summary.
|
|
6
|
+
*/
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import { getCoolifyConfig, getDnsConfig, getGlitchtipConfig, getHetznerConfig, getOpenpanelConfig, getResendConfig, getS3Config, getStore, } from "./config.js";
|
|
9
|
+
import { verifyCoolify } from "./utils/coolify-api.js";
|
|
10
|
+
import { execOk } from "./utils/exec.js";
|
|
11
|
+
import { SECRET_KEYS, getSecret } from "./utils/secrets.js";
|
|
12
|
+
async function check(name, fn, hintFn) {
|
|
13
|
+
try {
|
|
14
|
+
const detail = await fn();
|
|
15
|
+
return { name, status: "ok", detail: detail || undefined };
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
19
|
+
return { name, status: "fail", detail, hint: hintFn?.(detail) };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Pull the HTTP status code out of a "HTTP 401 ..." style error message. */
|
|
23
|
+
function httpCode(detail) {
|
|
24
|
+
const m = detail.match(/HTTP (\d{3})/);
|
|
25
|
+
return m ? Number(m[1]) : undefined;
|
|
26
|
+
}
|
|
27
|
+
async function checkGitHub() {
|
|
28
|
+
if (!(await execOk("gh", ["--version"]))) {
|
|
29
|
+
return {
|
|
30
|
+
name: "GitHub (gh CLI)",
|
|
31
|
+
status: "fail",
|
|
32
|
+
detail: "gh CLI not installed",
|
|
33
|
+
hint: [
|
|
34
|
+
"Install: `brew install gh` (macOS) or see https://cli.github.com",
|
|
35
|
+
"Then authenticate: `gh auth login`",
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (!(await execOk("gh", ["auth", "status"]))) {
|
|
40
|
+
return {
|
|
41
|
+
name: "GitHub (gh CLI)",
|
|
42
|
+
status: "fail",
|
|
43
|
+
detail: "not authenticated",
|
|
44
|
+
hint: ["Run `gh auth login` and pick GitHub.com → HTTPS → browser."],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return { name: "GitHub (gh CLI)", status: "ok" };
|
|
48
|
+
}
|
|
49
|
+
async function checkCoolify() {
|
|
50
|
+
const cfg = await getCoolifyConfig();
|
|
51
|
+
if (!cfg)
|
|
52
|
+
return { name: "Coolify", status: "skip" };
|
|
53
|
+
return check("Coolify", async () => {
|
|
54
|
+
const v = await verifyCoolify(cfg.url, cfg.token);
|
|
55
|
+
return `v${v}`;
|
|
56
|
+
}, (detail) => {
|
|
57
|
+
const code = httpCode(detail);
|
|
58
|
+
if (code === 401 || code === 403) {
|
|
59
|
+
return [
|
|
60
|
+
"API token invalid or expired.",
|
|
61
|
+
`Create a new one: ${cfg.url.replace(/\/$/, "")}/security/api-tokens`,
|
|
62
|
+
"Then re-run: `hatchkit config add coolify`",
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
if (/ENOTFOUND|ECONNREFUSED|fetch failed/i.test(detail)) {
|
|
66
|
+
return [
|
|
67
|
+
`Can't reach Coolify at ${cfg.url}.`,
|
|
68
|
+
"Check the URL is reachable from this machine, or re-run `hatchkit config add coolify`.",
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async function checkHetzner() {
|
|
75
|
+
const cfg = await getHetznerConfig();
|
|
76
|
+
if (!cfg)
|
|
77
|
+
return { name: "Hetzner Cloud", status: "skip" };
|
|
78
|
+
return check("Hetzner Cloud", async () => {
|
|
79
|
+
const res = await fetch("https://api.hetzner.cloud/v1/servers?per_page=1", {
|
|
80
|
+
headers: { Authorization: `Bearer ${cfg.token}` },
|
|
81
|
+
});
|
|
82
|
+
if (!res.ok)
|
|
83
|
+
throw new Error(`HTTP ${res.status}`);
|
|
84
|
+
const body = (await res.json());
|
|
85
|
+
return `${body.meta?.pagination?.total_entries ?? "?"} server(s)`;
|
|
86
|
+
}, (detail) => {
|
|
87
|
+
const code = httpCode(detail);
|
|
88
|
+
if (code === 401) {
|
|
89
|
+
return [
|
|
90
|
+
"Hetzner API token is invalid or was revoked.",
|
|
91
|
+
"Create a new one: https://console.hetzner.cloud/ → project → Security → API tokens (Read & Write)",
|
|
92
|
+
"Then re-run: `hatchkit config add hetzner`",
|
|
93
|
+
];
|
|
94
|
+
}
|
|
95
|
+
if (code === 403) {
|
|
96
|
+
return [
|
|
97
|
+
"Token lacks permissions — needs Read & Write on the project.",
|
|
98
|
+
"Re-create it and re-run `hatchkit config add hetzner`.",
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
return undefined;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
async function checkDns() {
|
|
105
|
+
const cfg = await getDnsConfig();
|
|
106
|
+
if (!cfg || cfg.provider === "manual")
|
|
107
|
+
return { name: "DNS", status: "skip" };
|
|
108
|
+
if (cfg.provider === "cloudflare") {
|
|
109
|
+
return check("DNS (Cloudflare)", async () => {
|
|
110
|
+
const res = await fetch("https://api.cloudflare.com/client/v4/user/tokens/verify", {
|
|
111
|
+
headers: { Authorization: `Bearer ${cfg.apiToken}` },
|
|
112
|
+
});
|
|
113
|
+
if (!res.ok)
|
|
114
|
+
throw new Error(`HTTP ${res.status}`);
|
|
115
|
+
const body = (await res.json());
|
|
116
|
+
return body.result?.status ?? "active";
|
|
117
|
+
}, (detail) => {
|
|
118
|
+
const code = httpCode(detail);
|
|
119
|
+
if (code === 401) {
|
|
120
|
+
return [
|
|
121
|
+
"Cloudflare API token is invalid, expired, or revoked.",
|
|
122
|
+
"Create a new one: https://dash.cloudflare.com/profile/api-tokens",
|
|
123
|
+
"Required permissions: Zone:DNS:Edit + Zone:Zone:Read (scope to the zones you'll use).",
|
|
124
|
+
"Then re-run: `hatchkit config add dns`",
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
if (code === 403) {
|
|
128
|
+
return [
|
|
129
|
+
"Token authenticates but lacks Zone:DNS:Edit + Zone:Zone:Read on the target zones.",
|
|
130
|
+
"Edit the token at https://dash.cloudflare.com/profile/api-tokens or create a new one, then `hatchkit config add dns`.",
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
return undefined;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// INWX uses XML-RPC login — skip active-verify (cheap check would require a login call).
|
|
137
|
+
return {
|
|
138
|
+
name: "DNS (INWX)",
|
|
139
|
+
status: "ok",
|
|
140
|
+
detail: "credentials stored (not test-authenticated)",
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
async function checkS3(provider) {
|
|
144
|
+
const name = `S3 (${provider})`;
|
|
145
|
+
const cfg = await getS3Config(provider);
|
|
146
|
+
if (!cfg)
|
|
147
|
+
return { name, status: "skip" };
|
|
148
|
+
// Stored creds only — a real verify would require an AWS SDK call.
|
|
149
|
+
return { name, status: "ok", detail: "credentials stored (endpoint set)" };
|
|
150
|
+
}
|
|
151
|
+
async function checkGpu(platform) {
|
|
152
|
+
const store = getStore();
|
|
153
|
+
const meta = store.get(`providers.gpu.${platform}`);
|
|
154
|
+
const name = `GPU (${platform})`;
|
|
155
|
+
if (meta?.status !== "configured")
|
|
156
|
+
return { name, status: "skip" };
|
|
157
|
+
if (platform === "modal") {
|
|
158
|
+
return check(name, async () => {
|
|
159
|
+
if (!(await execOk("modal", ["token", "current"])))
|
|
160
|
+
throw new Error("`modal token current` failed");
|
|
161
|
+
return "authenticated";
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
const key = await getSecret(SECRET_KEYS.gpuApiKey(platform));
|
|
165
|
+
if (!key) {
|
|
166
|
+
return {
|
|
167
|
+
name,
|
|
168
|
+
status: "fail",
|
|
169
|
+
detail: "API key missing from keychain",
|
|
170
|
+
hint: [`Re-run: \`hatchkit config add gpu\` and pick ${platform}.`],
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const gpuHint = (label, createUrl) => (detail) => {
|
|
174
|
+
const code = httpCode(detail);
|
|
175
|
+
if (code === 401 || code === 403) {
|
|
176
|
+
return [
|
|
177
|
+
`${label} API key is invalid or expired.`,
|
|
178
|
+
`Create a new one: ${createUrl}`,
|
|
179
|
+
"Then re-run: `hatchkit config add gpu`",
|
|
180
|
+
];
|
|
181
|
+
}
|
|
182
|
+
return undefined;
|
|
183
|
+
};
|
|
184
|
+
if (platform === "hf") {
|
|
185
|
+
return check(name, async () => {
|
|
186
|
+
const res = await fetch("https://huggingface.co/api/whoami-v2", {
|
|
187
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
188
|
+
});
|
|
189
|
+
if (!res.ok)
|
|
190
|
+
throw new Error(`HTTP ${res.status}`);
|
|
191
|
+
const body = (await res.json());
|
|
192
|
+
return body.name ?? "authenticated";
|
|
193
|
+
}, gpuHint("Hugging Face", "https://huggingface.co/settings/tokens"));
|
|
194
|
+
}
|
|
195
|
+
if (platform === "replicate") {
|
|
196
|
+
return check(name, async () => {
|
|
197
|
+
const res = await fetch("https://api.replicate.com/v1/account", {
|
|
198
|
+
headers: { Authorization: `Token ${key}` },
|
|
199
|
+
});
|
|
200
|
+
if (!res.ok)
|
|
201
|
+
throw new Error(`HTTP ${res.status}`);
|
|
202
|
+
return "authenticated";
|
|
203
|
+
}, gpuHint("Replicate", "https://replicate.com/account/api-tokens"));
|
|
204
|
+
}
|
|
205
|
+
if (platform === "runpod") {
|
|
206
|
+
return check(name, async () => {
|
|
207
|
+
const res = await fetch("https://rest.runpod.io/v1/user", {
|
|
208
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
209
|
+
});
|
|
210
|
+
if (!res.ok)
|
|
211
|
+
throw new Error(`HTTP ${res.status}`);
|
|
212
|
+
return "authenticated";
|
|
213
|
+
}, gpuHint("RunPod", "https://www.runpod.io/console/user/settings"));
|
|
214
|
+
}
|
|
215
|
+
return { name, status: "ok", detail: "credentials stored" };
|
|
216
|
+
}
|
|
217
|
+
async function checkGlitchtip() {
|
|
218
|
+
const cfg = await getGlitchtipConfig();
|
|
219
|
+
if (!cfg)
|
|
220
|
+
return { name: "GlitchTip", status: "skip" };
|
|
221
|
+
return check("GlitchTip", async () => {
|
|
222
|
+
const res = await fetch(`${cfg.url}/api/0/organizations/${cfg.organizationSlug}/`, {
|
|
223
|
+
headers: { Authorization: `Bearer ${cfg.token}` },
|
|
224
|
+
});
|
|
225
|
+
if (!res.ok)
|
|
226
|
+
throw new Error(`HTTP ${res.status}`);
|
|
227
|
+
return `org: ${cfg.organizationSlug}`;
|
|
228
|
+
}, (detail) => {
|
|
229
|
+
const code = httpCode(detail);
|
|
230
|
+
const base = cfg.url.replace(/\/$/, "");
|
|
231
|
+
if (code === 401) {
|
|
232
|
+
return [
|
|
233
|
+
"Auth token is invalid or expired.",
|
|
234
|
+
`Create a new one: ${base}/profile/auth-tokens`,
|
|
235
|
+
"Then re-run: `hatchkit config add glitchtip`",
|
|
236
|
+
];
|
|
237
|
+
}
|
|
238
|
+
if (code === 404) {
|
|
239
|
+
return [
|
|
240
|
+
`Organization "${cfg.organizationSlug}" not found — slug may be wrong.`,
|
|
241
|
+
`Check at ${base}/ and re-run: \`hatchkit config add glitchtip\``,
|
|
242
|
+
];
|
|
243
|
+
}
|
|
244
|
+
return undefined;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
async function checkOpenpanel() {
|
|
248
|
+
const cfg = await getOpenpanelConfig();
|
|
249
|
+
if (!cfg)
|
|
250
|
+
return { name: "OpenPanel", status: "skip" };
|
|
251
|
+
const manageBase = `${(cfg.apiUrl ?? cfg.url).replace(/\/$/, "")}/manage`;
|
|
252
|
+
return check("OpenPanel", async () => {
|
|
253
|
+
const res = await fetch(`${manageBase}/projects`, {
|
|
254
|
+
headers: {
|
|
255
|
+
"openpanel-client-id": cfg.rootClientId,
|
|
256
|
+
"openpanel-client-secret": cfg.rootClientSecret,
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
if (!res.ok)
|
|
260
|
+
throw new Error(`HTTP ${res.status}`);
|
|
261
|
+
return `root client OK`;
|
|
262
|
+
}, (detail) => {
|
|
263
|
+
const code = httpCode(detail);
|
|
264
|
+
if (code === 401 || code === 403) {
|
|
265
|
+
return [
|
|
266
|
+
"Root client credentials rejected — may have been rotated or lack `write` access.",
|
|
267
|
+
"Re-run: `hatchkit config add openpanel` and paste the root client id/secret.",
|
|
268
|
+
];
|
|
269
|
+
}
|
|
270
|
+
if (/Only HTML requests|<html/i.test(detail) || code === 404) {
|
|
271
|
+
return [
|
|
272
|
+
`Management API base URL looks wrong — response isn't JSON.`,
|
|
273
|
+
`Current: ${manageBase}`,
|
|
274
|
+
"Self-hosted OpenPanel puts the API on a separate subdomain (typically `api.<dashboard>`).",
|
|
275
|
+
"Re-run: `hatchkit config add openpanel` and set the API URL explicitly.",
|
|
276
|
+
];
|
|
277
|
+
}
|
|
278
|
+
return undefined;
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
async function checkResend() {
|
|
282
|
+
const cfg = await getResendConfig();
|
|
283
|
+
if (!cfg)
|
|
284
|
+
return { name: "Resend", status: "skip" };
|
|
285
|
+
return check("Resend", async () => {
|
|
286
|
+
const res = await fetch("https://api.resend.com/domains", {
|
|
287
|
+
headers: { Authorization: `Bearer ${cfg.apiKey}` },
|
|
288
|
+
});
|
|
289
|
+
if (!res.ok)
|
|
290
|
+
throw new Error(`HTTP ${res.status}`);
|
|
291
|
+
return "API key valid";
|
|
292
|
+
}, (detail) => {
|
|
293
|
+
const code = httpCode(detail);
|
|
294
|
+
if (code === 401) {
|
|
295
|
+
return [
|
|
296
|
+
"Resend API key is invalid or was deleted.",
|
|
297
|
+
"Create a new one (full access): https://resend.com/api-keys",
|
|
298
|
+
"Then re-run: `hatchkit config add resend`",
|
|
299
|
+
];
|
|
300
|
+
}
|
|
301
|
+
if (code === 403) {
|
|
302
|
+
return [
|
|
303
|
+
"API key lacks permissions — needs `Full access` to list/create domains and keys.",
|
|
304
|
+
"Re-create at https://resend.com/api-keys and re-run `hatchkit config add resend`.",
|
|
305
|
+
];
|
|
306
|
+
}
|
|
307
|
+
return undefined;
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
export async function collectDoctorResults() {
|
|
311
|
+
const results = [];
|
|
312
|
+
results.push(await checkGitHub());
|
|
313
|
+
results.push(await checkCoolify());
|
|
314
|
+
results.push(await checkHetzner());
|
|
315
|
+
results.push(await checkDns());
|
|
316
|
+
for (const p of ["hetzner", "aws", "r2"])
|
|
317
|
+
results.push(await checkS3(p));
|
|
318
|
+
for (const p of ["modal", "runpod", "hf", "replicate"])
|
|
319
|
+
results.push(await checkGpu(p));
|
|
320
|
+
results.push(await checkGlitchtip());
|
|
321
|
+
results.push(await checkOpenpanel());
|
|
322
|
+
results.push(await checkResend());
|
|
323
|
+
return results;
|
|
324
|
+
}
|
|
325
|
+
export async function runDoctor(opts = {}) {
|
|
326
|
+
const results = await collectDoctorResults();
|
|
327
|
+
const okCount = results.filter((r) => r.status === "ok").length;
|
|
328
|
+
const failCount = results.filter((r) => r.status === "fail").length;
|
|
329
|
+
const skipCount = results.filter((r) => r.status === "skip").length;
|
|
330
|
+
if (opts.json) {
|
|
331
|
+
const payload = {
|
|
332
|
+
summary: { ok: okCount, failing: failCount, not_configured: skipCount },
|
|
333
|
+
checks: results.map((r) => ({
|
|
334
|
+
name: r.name,
|
|
335
|
+
status: r.status,
|
|
336
|
+
detail: r.detail,
|
|
337
|
+
hint: r.hint,
|
|
338
|
+
})),
|
|
339
|
+
};
|
|
340
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
341
|
+
if (failCount > 0)
|
|
342
|
+
process.exit(1);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
console.log(chalk.bold(" hatchkit doctor — checking configured providers\n"));
|
|
346
|
+
for (const r of results) {
|
|
347
|
+
const icon = r.status === "ok" ? chalk.green("✓") : r.status === "fail" ? chalk.red("✗") : chalk.dim("·");
|
|
348
|
+
const name = r.status === "fail" ? chalk.red(r.name) : r.name;
|
|
349
|
+
const detail = r.detail ? chalk.dim(` — ${r.detail}`) : "";
|
|
350
|
+
console.log(` ${icon} ${name}${detail}`);
|
|
351
|
+
}
|
|
352
|
+
console.log(`\n ${chalk.green(`${okCount} ok`)} ${failCount ? chalk.red(`${failCount} failing`) : chalk.dim("0 failing")} ${chalk.dim(`${skipCount} not configured`)}\n`);
|
|
353
|
+
const failed = results.filter((r) => r.status === "fail");
|
|
354
|
+
if (failed.length > 0) {
|
|
355
|
+
console.log(chalk.bold(" How to fix"));
|
|
356
|
+
for (const r of failed) {
|
|
357
|
+
console.log(`\n ${chalk.red("✗")} ${chalk.bold(r.name)}`);
|
|
358
|
+
const lines = r.hint ?? [
|
|
359
|
+
"No specific hint — try re-running the relevant `hatchkit config add <provider>` to re-enter credentials.",
|
|
360
|
+
];
|
|
361
|
+
for (const line of lines)
|
|
362
|
+
console.log(` ${chalk.dim("→")} ${line}`);
|
|
363
|
+
}
|
|
364
|
+
console.log();
|
|
365
|
+
process.exit(1);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../src/explain.ts"],"names":[],"mappings":"AAqJA,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAoD7D"}
|
package/dist/explain.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `hatchkit explain` — one-page mental model. Written so a human with
|
|
3
|
+
* zero context (or an agent encountering hatchkit for the first time)
|
|
4
|
+
* can read it top-to-bottom and understand what the CLI does, what it
|
|
5
|
+
* owns, and the canonical workflow.
|
|
6
|
+
*
|
|
7
|
+
* Update the `CONCEPTS` / `COMMANDS` / `WORKFLOW` blocks in one place
|
|
8
|
+
* and both the human text and the JSON payload stay in sync.
|
|
9
|
+
*/
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
const MODEL = {
|
|
12
|
+
tagline: "Scaffold, deploy, and provision full-stack projects on your own infra.",
|
|
13
|
+
what_it_does: [
|
|
14
|
+
"Scaffolds opinionated full-stack projects (web + optional desktop/mobile + optional ML) from a starter template.",
|
|
15
|
+
"Wires them up to your own infra: Hetzner (server), DNS (Cloudflare/INWX), Coolify (deploys), GitHub (repo).",
|
|
16
|
+
"Provisions per-project clients in third-party services (GlitchTip errors, OpenPanel analytics, Resend email).",
|
|
17
|
+
"Manages per-project dotenvx private keys in your OS keychain.",
|
|
18
|
+
],
|
|
19
|
+
concepts: [
|
|
20
|
+
{
|
|
21
|
+
name: "Provider",
|
|
22
|
+
description: "An external service (GitHub, Hetzner, Coolify, DNS, S3, GPU, GlitchTip, OpenPanel, Resend). Each is configured once; credentials go to the OS keychain, metadata to ~/<conf-dir>/config.json.",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: "Project",
|
|
26
|
+
description: "A scaffolded repo with a .hatchkit.json manifest. Has a name (kebab-case), a domain, a feature set (desktop/mobile/s3/ml), and per-project ports.",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "Client",
|
|
30
|
+
description: "A per-project credential in a provider — e.g. a Resend API key scoped to one project, a GlitchTip DSN, an OpenPanel client id/secret. `hatchkit add` creates `-dev` and `-prod` pairs.",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "Manifest",
|
|
34
|
+
description: ".hatchkit.json at the project root. Records which features were scaffolded so `hatchkit update` knows what's already there.",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "dotenvx key",
|
|
38
|
+
description: "Per-project private key that decrypts .env.production at runtime. Generated at scaffold time; lives in the OS keychain under service `hatchkit`; pushed to Coolify via `hatchkit keys push`.",
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
commands: [
|
|
42
|
+
{
|
|
43
|
+
name: "hatchkit setup",
|
|
44
|
+
summary: "One-time onboarding — wires up GitHub + Coolify + Hetzner + DNS + optional extras.",
|
|
45
|
+
when: "First time you ever use hatchkit on a machine.",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: "hatchkit status",
|
|
49
|
+
summary: "Show which providers are configured and what's the next best step.",
|
|
50
|
+
when: "To get oriented, or after setup to confirm state.",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "hatchkit doctor",
|
|
54
|
+
summary: "Live-verify every configured provider with a read-only API call; contextual fix hints on failures.",
|
|
55
|
+
when: "When something's broken, before a deploy, or as a CI sanity check.",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "hatchkit create",
|
|
59
|
+
summary: "Scaffold (and optionally deploy) a new project. Interactive.",
|
|
60
|
+
when: "Starting a new project.",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "hatchkit update",
|
|
64
|
+
summary: "Add features (desktop, mobile) to an already-scaffolded project.",
|
|
65
|
+
when: "`cd <project-dir>` first; expands an existing scaffold.",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "hatchkit add <project>",
|
|
69
|
+
summary: "Provision GlitchTip / OpenPanel / Resend clients for an existing project (creates -dev + -prod pair each).",
|
|
70
|
+
when: "After the scaffold is live and you're ready to wire up observability / email.",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "hatchkit keys show <project>",
|
|
74
|
+
summary: "Print the project's DOTENV_PRIVATE_KEY_PRODUCTION from the keychain.",
|
|
75
|
+
when: "To hand the key to CI / another machine / manually paste into Coolify.",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "hatchkit keys push <project>",
|
|
79
|
+
summary: "Upsert the private key onto the project's Coolify app via API.",
|
|
80
|
+
when: "After scaffold + initial Coolify deploy, so the app can decrypt env at runtime.",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: "hatchkit config add <provider>",
|
|
84
|
+
summary: "Configure one provider (coolify / hetzner / dns / s3 / gpu / glitchtip / openpanel / resend).",
|
|
85
|
+
when: "Rotating a token, or adding an optional provider you skipped during setup.",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: "hatchkit explain",
|
|
89
|
+
summary: "This screen. `--json` for a structured payload.",
|
|
90
|
+
when: "Anytime a zero-context reader (human or agent) needs the mental model.",
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
workflow: [
|
|
94
|
+
"1. `hatchkit setup` — configure credentials once (per machine).",
|
|
95
|
+
"2. `hatchkit status` — confirm everything's green.",
|
|
96
|
+
"3. `hatchkit create` — scaffold a new project; pick features, deploy target, ML services.",
|
|
97
|
+
"4. `hatchkit add <project>` — provision per-project clients (GlitchTip, OpenPanel, Resend).",
|
|
98
|
+
"5. `hatchkit keys push <project>` — ship the dotenvx key to Coolify so prod can decrypt.",
|
|
99
|
+
"6. `hatchkit doctor` — sanity-check before/after anything risky.",
|
|
100
|
+
"7. `hatchkit update` (from project dir) — extend an existing project with new features.",
|
|
101
|
+
],
|
|
102
|
+
provider_glossary: [
|
|
103
|
+
{ name: "GitHub", role: "Hosts the project repo. Uses the `gh` CLI for auth." },
|
|
104
|
+
{ name: "Coolify", role: "Self-hosted PaaS. Deploys apps on your Hetzner box." },
|
|
105
|
+
{ name: "Hetzner Cloud", role: "VMs (and optional S3 object storage) for new deploy targets." },
|
|
106
|
+
{ name: "DNS (Cloudflare / INWX)", role: "Automates domain records during Terraform." },
|
|
107
|
+
{ name: "S3 (Hetzner / AWS / R2)", role: "Optional object storage — picked per-project." },
|
|
108
|
+
{
|
|
109
|
+
name: "GPU (Modal / RunPod / HF / Replicate)",
|
|
110
|
+
role: "Optional inference backends for ML services.",
|
|
111
|
+
},
|
|
112
|
+
{ name: "GlitchTip", role: "Self-hostable Sentry-compatible error tracking." },
|
|
113
|
+
{ name: "OpenPanel", role: "Privacy-friendly product analytics." },
|
|
114
|
+
{ name: "Resend", role: "Transactional email; keys can be scoped to a sending domain." },
|
|
115
|
+
],
|
|
116
|
+
state_locations: [
|
|
117
|
+
{
|
|
118
|
+
what: "Provider metadata (no secrets)",
|
|
119
|
+
where: "~/<conf-dir>/config.json via the `conf` package",
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
what: "Secrets (tokens, keys)",
|
|
123
|
+
where: "OS keychain under service `hatchkit` (macOS Keychain / libsecret)",
|
|
124
|
+
},
|
|
125
|
+
{ what: "Provisioned env blocks", where: "~/<conf-dir>/provisioned/<project>.{dev,prod}.env" },
|
|
126
|
+
{ what: "Project manifest", where: "<project-dir>/.hatchkit.json" },
|
|
127
|
+
],
|
|
128
|
+
};
|
|
129
|
+
export function renderExplain(opts) {
|
|
130
|
+
if (opts.json) {
|
|
131
|
+
return JSON.stringify(MODEL, null, 2);
|
|
132
|
+
}
|
|
133
|
+
const out = [];
|
|
134
|
+
const b = (s) => chalk.bold(s);
|
|
135
|
+
const dim = (s) => chalk.dim(s);
|
|
136
|
+
out.push(b(" hatchkit — the mental model"));
|
|
137
|
+
out.push(` ${MODEL.tagline}`);
|
|
138
|
+
out.push("");
|
|
139
|
+
out.push(b(" What it does"));
|
|
140
|
+
for (const line of MODEL.what_it_does)
|
|
141
|
+
out.push(` · ${line}`);
|
|
142
|
+
out.push("");
|
|
143
|
+
out.push(b(" Concepts"));
|
|
144
|
+
for (const c of MODEL.concepts) {
|
|
145
|
+
out.push(` ${chalk.cyan(c.name)}`);
|
|
146
|
+
out.push(` ${c.description}`);
|
|
147
|
+
}
|
|
148
|
+
out.push("");
|
|
149
|
+
out.push(b(" Commands"));
|
|
150
|
+
for (const c of MODEL.commands) {
|
|
151
|
+
out.push(` ${chalk.cyan(c.name.padEnd(30))} ${c.summary}`);
|
|
152
|
+
out.push(` ${dim(`when: ${c.when}`)}`);
|
|
153
|
+
}
|
|
154
|
+
out.push("");
|
|
155
|
+
out.push(b(" Canonical workflow"));
|
|
156
|
+
for (const line of MODEL.workflow)
|
|
157
|
+
out.push(` ${line}`);
|
|
158
|
+
out.push("");
|
|
159
|
+
out.push(b(" Providers at a glance"));
|
|
160
|
+
for (const p of MODEL.provider_glossary) {
|
|
161
|
+
out.push(` ${chalk.cyan(p.name.padEnd(32))} ${p.role}`);
|
|
162
|
+
}
|
|
163
|
+
out.push("");
|
|
164
|
+
out.push(b(" Where state lives"));
|
|
165
|
+
for (const s of MODEL.state_locations) {
|
|
166
|
+
out.push(` ${chalk.cyan(s.what.padEnd(32))} ${s.where}`);
|
|
167
|
+
}
|
|
168
|
+
out.push("");
|
|
169
|
+
out.push(dim(" Tip: `hatchkit status --json` and `hatchkit doctor --json` give agents a machine-readable view."));
|
|
170
|
+
out.push("");
|
|
171
|
+
return out.join("\n");
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=explain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../src/explain.ts"],"names":[],"mappings":"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"}
|