kizlo 0.9.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/cli/commands/_setup.js +132 -79
- package/dist/cli/commands/_wiring.js +5 -4
- package/dist/cli/commands/create.js +35 -28
- package/dist/cli/commands/dev.js +172 -87
- package/dist/cli/commands/init.js +97 -103
- package/dist/cli/commands/test.js +34 -34
- package/dist/cli/daemon/config.js +18 -24
- package/dist/cli/daemon/logger.js +1 -1
- package/dist/cli/daemon/reload.js +66 -0
- package/dist/cli/daemon/watch.js +0 -1
- package/dist/cli/presets/base.js +4 -2
- package/dist/cli/presets/nextjs.js +0 -1
- package/dist/cli/presets/template.js +104 -18
- package/dist/cli/utils.js +41 -19
- package/dist/cli/wp/compose/override.js +3 -3
- package/dist/cli/wp/compose/override.test.ts +2 -2
- package/dist/cli/wp/compose/override.ts +3 -3
- package/dist/cli/wp/constants.d.ts +10 -4
- package/dist/cli/wp/constants.js +10 -4
- package/dist/cli/wp/dev.js +13 -58
- package/dist/cli/wp/docker.d.ts +16 -4
- package/dist/cli/wp/docker.js +20 -7
- package/dist/cli/wp/settings.js +9 -3
- package/dist/cli/wp/setup.js +1 -1
- package/dist/cli/wp/stack.js +4 -4
- package/dist/comment/schema.js +2 -2
- package/dist/config.d.ts +20 -23
- package/dist/context.d.ts +9 -0
- package/dist/context.js +20 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/integrations/nextjs/kizlo.server.js +1 -1
- package/dist/integrations/nextjs/utils.js +2 -2
- package/dist/kizlo.d.ts +16 -16
- package/dist/kizlo.js +19 -15
- package/dist/package.js +1 -1
- package/dist/page/schema.js +2 -2
- package/dist/post/schema.js +2 -2
- package/dist/router.d.ts +9 -9
- package/dist/shared/schema.d.ts +1 -2
- package/dist/shared/schema.js +2 -2
- package/dist/test/server.js +1 -1
- package/dist/test.d.ts +3 -3
- package/dist/test.js +3 -3
- package/dist/wordpress/service.d.ts +4 -0
- package/dist/wordpress/service.js +5 -0
- package/package.json +2 -2
- package/dist/cli/wp/byo.js +0 -113
package/dist/cli/commands/dev.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { createStack } from "../wp/docker.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { createStack, dockerHint, dockerStatus } from "../wp/docker.js";
|
|
2
|
+
import { findConfigDir } from "../wp/utils.js";
|
|
3
|
+
import { log } from "../daemon/logger.js";
|
|
4
|
+
import { DEFAULT_ENV_KEYS, ensureGitignored, envGroups, groupDefault, mergeEnv, pickStackPort, withSpinner } from "../utils.js";
|
|
5
|
+
import { resolveDevConfig, usesLocalWordPress } from "../daemon/config.js";
|
|
4
6
|
import { bootstrapDev } from "../wp/dev.js";
|
|
5
7
|
import { reapOrphans, registerSession, removeProjectContainers, spawnWatchdog, unregisterSession } from "../wp/session.js";
|
|
6
8
|
import { syncSiteSettings } from "../wp/settings.js";
|
|
7
9
|
import { devStack } from "../wp/stack.js";
|
|
8
10
|
import { palette } from "../banner.js";
|
|
11
|
+
import { watchReload } from "../daemon/reload.js";
|
|
9
12
|
import { startWatcher } from "../daemon/watch.js";
|
|
10
13
|
import { join } from "node:path";
|
|
11
14
|
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
@@ -21,15 +24,13 @@ async function resolve$1(cwd) {
|
|
|
21
24
|
};
|
|
22
25
|
}
|
|
23
26
|
/**
|
|
24
|
-
* The
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* print a plain note explaining there's nothing to do and exit cleanly. Returns true when a
|
|
28
|
-
* local stack is configured and the caller may proceed.
|
|
27
|
+
* The lifecycle subcommands (`stop`/`reset`) only act on local WordPress. A project pointing at its
|
|
28
|
+
* own WordPress (no `dev.local`) has nothing to manage, so print a plain note and exit cleanly. Returns
|
|
29
|
+
* true when local WordPress is configured and the caller may proceed.
|
|
29
30
|
*/
|
|
30
|
-
async function
|
|
31
|
-
if (await
|
|
32
|
-
note("
|
|
31
|
+
async function requireLocalWordPress(cwd) {
|
|
32
|
+
if (await usesLocalWordPress(cwd)) return true;
|
|
33
|
+
note("This project doesn't run local WordPress — set `dev.local: true` in kizlo.config.ts to add it.");
|
|
33
34
|
return false;
|
|
34
35
|
}
|
|
35
36
|
/** A dim, untagged one-liner (no consola timestamp) for the clean dev output. */
|
|
@@ -39,7 +40,7 @@ function note(text) {
|
|
|
39
40
|
}
|
|
40
41
|
/**
|
|
41
42
|
* Print the connection summary as an aligned, Next.js-style block. Shows the wp-admin URL on
|
|
42
|
-
* the loopback ("Local") and — when
|
|
43
|
+
* the loopback ("Local") and — when local WordPress is installed on a LAN address rather than
|
|
43
44
|
* localhost — on the network, so it can be opened from other devices. On a fresh install, also
|
|
44
45
|
* show the one-time wp-admin password (it's never stored, so this is the only chance to see it).
|
|
45
46
|
*/
|
|
@@ -52,57 +53,56 @@ function printSummary(info) {
|
|
|
52
53
|
const width = Math.max(...rows.map(([label]) => label.length)) + 1;
|
|
53
54
|
const lines = ["", ...rows.map(([label, value]) => ` ${dim}- ${`${label}:`.padEnd(width)}${reset} ${cyan}${value}${reset}`)];
|
|
54
55
|
if (info.secrets) lines.push("", ` ${dim}admin login:${reset} ${info.username} / ${info.secrets.password}`, ` ${dim}save the password now — it's shown only once${reset}`);
|
|
55
|
-
else if (info.imported) lines.push("", ` ${dim}log in with your imported site's own credentials${reset}`);
|
|
56
56
|
if (info.seeded > 0) lines.push(` ${dim}seeded ${info.seeded} fixture${info.seeded === 1 ? "" : "s"}${reset}`);
|
|
57
57
|
process.stdout.write(`${lines.join("\n")}\n`);
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* touched by `kizlo dev`, so pointing them at a real site survives booting
|
|
60
|
+
* Local-WordPress connection keys a fresh install must rewrite (the rest of `.env` is untouched). The
|
|
61
|
+
* remote `KIZLO_WP_*` / `KIZLO_WP_SECRET` keys live under their own names and are never
|
|
62
|
+
* touched by `kizlo dev`, so pointing them at a real site survives booting local WordPress.
|
|
63
63
|
*/
|
|
64
64
|
const WP_ENV_KEYS = [
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
65
|
+
"KIZLO_LOCAL_WP_URL",
|
|
66
|
+
"KIZLO_LOCAL_WP_USERNAME",
|
|
67
|
+
"KIZLO_LOCAL_WP_APP_PASSWORD"
|
|
68
68
|
];
|
|
69
69
|
/** Read a key's value from raw `.env` content (first match, trimmed); undefined when absent or empty. */
|
|
70
70
|
function readEnvValue(content, key) {
|
|
71
71
|
return content.match(new RegExp(`^\\s*${key}\\s*=\\s*(.*)$`, "m"))?.[1]?.trim() || void 0;
|
|
72
72
|
}
|
|
73
73
|
/**
|
|
74
|
-
* The Kizlo backend URL from `.env` — the one key ending in `
|
|
75
|
-
* or a framework-prefixed `
|
|
74
|
+
* The Kizlo backend URL from `.env` — the one key ending in `KIZLO_API_URL` (`KIZLO_API_URL`,
|
|
75
|
+
* or a framework-prefixed `NEXT_PUBLIC_KIZLO_API_URL`). It's the handler mount the plugin delivers
|
|
76
76
|
* webhook events to; its origin is the site's canonical URL. User-managed (init writes it), so dev
|
|
77
77
|
* only reads it. Undefined before `kizlo init` has populated `.env`.
|
|
78
78
|
*/
|
|
79
79
|
function readBaseUrl(content) {
|
|
80
|
-
return content.match(/^\s*[A-Z_]*
|
|
80
|
+
return content.match(/^\s*[A-Z_]*KIZLO_API_URL\s*=\s*(.*)$/m)?.[1]?.trim() || void 0;
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
|
-
* Rewrite the
|
|
83
|
+
* Rewrite the local WordPress connection in `.env` after a fresh install. A reset (or first boot)
|
|
84
84
|
* wipes the database, so the previous application password — and possibly the port — no longer
|
|
85
85
|
* match; without this the app keeps the stale credentials and REST auth fails. Only the three
|
|
86
86
|
* connection keys are overwritten; everything else in `.env` is preserved, and the file is created
|
|
87
87
|
* if absent. Gated by the caller on a minted `appPassword`, so a warm resume never churns it.
|
|
88
88
|
*
|
|
89
|
-
* `
|
|
90
|
-
* value the user already set is preserved — booting
|
|
91
|
-
* resolved
|
|
92
|
-
* returned so the caller can sync them into the plugin.
|
|
89
|
+
* `KIZLO_CONNECT=local` and `KIZLO_LOCAL_WP_SECRET` are written too but kept out of the overwrite set,
|
|
90
|
+
* so a value the user already set is preserved — booting local WordPress only fills them when absent.
|
|
91
|
+
* The resolved local secret (the existing one, or a freshly minted one) and the Kizlo server base URL
|
|
92
|
+
* are returned so the caller can sync them into the plugin.
|
|
93
93
|
*/
|
|
94
94
|
function updateWpEnv(cfg, info) {
|
|
95
95
|
if (!info.appPassword) return void 0;
|
|
96
96
|
const envPath = join(cfg.configDir, ".env");
|
|
97
97
|
const existing = existsSync(envPath) ? readFileSync(envPath, "utf8") : "";
|
|
98
|
-
const siteSecret = readEnvValue(existing, "
|
|
98
|
+
const siteSecret = readEnvValue(existing, "KIZLO_LOCAL_WP_SECRET") ?? randomBytes(32).toString("hex");
|
|
99
99
|
const { content } = mergeEnv(existing, {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}, new Set(WP_ENV_KEYS), envGroups(
|
|
100
|
+
KIZLO_LOCAL_WP_URL: info.url,
|
|
101
|
+
KIZLO_LOCAL_WP_USERNAME: info.username,
|
|
102
|
+
KIZLO_LOCAL_WP_APP_PASSWORD: info.appPassword,
|
|
103
|
+
KIZLO_LOCAL_WP_SECRET: siteSecret,
|
|
104
|
+
KIZLO_CONNECT: "local"
|
|
105
|
+
}, new Set(WP_ENV_KEYS), envGroups(DEFAULT_ENV_KEYS));
|
|
106
106
|
writeFileSync(envPath, content);
|
|
107
107
|
return {
|
|
108
108
|
siteSecret,
|
|
@@ -110,19 +110,19 @@ function updateWpEnv(cfg, info) {
|
|
|
110
110
|
};
|
|
111
111
|
}
|
|
112
112
|
/**
|
|
113
|
-
* Re-point `
|
|
113
|
+
* Re-point `KIZLO_LOCAL_WP_URL` at the current URL on a warm resume, so a LAN address that
|
|
114
114
|
* changed since the last session (a new DHCP lease, a different network) doesn't leave the app talking
|
|
115
115
|
* to a dead IP. Only this one key is rewritten — the credentials and secret from the fresh install are
|
|
116
116
|
* preserved — and it's a no-op when `.env` is absent (nothing provisioned yet) or already current.
|
|
117
117
|
* The full fresh-install write goes through {@link updateWpEnv} instead; this covers the resume path it
|
|
118
118
|
* skips. Returns true when it changed the file. The app still needs a restart to read the new value.
|
|
119
119
|
*/
|
|
120
|
-
function
|
|
120
|
+
function syncLocalUrl(cfg, url) {
|
|
121
121
|
const envPath = join(cfg.configDir, ".env");
|
|
122
122
|
if (!existsSync(envPath)) return false;
|
|
123
123
|
const existing = readFileSync(envPath, "utf8");
|
|
124
|
-
if (readEnvValue(existing, "
|
|
125
|
-
const { content } = mergeEnv(existing, {
|
|
124
|
+
if (readEnvValue(existing, "KIZLO_LOCAL_WP_URL") === url) return false;
|
|
125
|
+
const { content } = mergeEnv(existing, { KIZLO_LOCAL_WP_URL: url }, new Set(["KIZLO_LOCAL_WP_URL"]), envGroups(DEFAULT_ENV_KEYS));
|
|
126
126
|
writeFileSync(envPath, content);
|
|
127
127
|
return true;
|
|
128
128
|
}
|
|
@@ -134,7 +134,7 @@ function syncDevUrl(cfg, url) {
|
|
|
134
134
|
* `next dev` child server — nothing stops them automatically when we die. A dying process
|
|
135
135
|
* also can't be trusted to finish async work (a closed terminal breaks its stdout
|
|
136
136
|
* mid-write), so this process does no docker work on the way out. It only needs to
|
|
137
|
-
* *exit*; the watchdog, watching our PID from its own session, stops
|
|
137
|
+
* *exit*; the watchdog, watching our PID from its own session, stops it the moment
|
|
138
138
|
* we're gone — by Ctrl+C, SIGTERM, a closed tab, SIGKILL, or a crash alike.
|
|
139
139
|
*
|
|
140
140
|
* We trigger that exit two ways, because neither alone is enough: signal handlers (for
|
|
@@ -150,7 +150,7 @@ function armForegroundTeardown(cfg) {
|
|
|
150
150
|
exiting = true;
|
|
151
151
|
unregisterSession(cfg.project);
|
|
152
152
|
try {
|
|
153
|
-
note(`Stopping
|
|
153
|
+
note(`Stopping local WordPress (${reason})…`);
|
|
154
154
|
} catch {}
|
|
155
155
|
process.exit(0);
|
|
156
156
|
};
|
|
@@ -169,13 +169,13 @@ function armForegroundTeardown(cfg) {
|
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
/**
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
172
|
+
* Bring the dev stack's containers up for `cfg`: clear any stale containers, resolve the published
|
|
173
|
+
* ports (stepping off a collision unless the port is pinned in config), write the compose files, and
|
|
174
|
+
* note any port that moved. Returns `cfg` with the resolved ports — the shape the rest of the boot
|
|
175
|
+
* and the teardown work against. Shared by the first boot and every reload reboot, so a changed
|
|
176
|
+
* `dev.port` in `kizlo.config.ts` is re-resolved the same way each time.
|
|
177
177
|
*/
|
|
178
|
-
async function
|
|
178
|
+
async function prepareStack(cfg) {
|
|
179
179
|
await removeProjectContainers(cfg.project);
|
|
180
180
|
const port = await pickStackPort(cfg.port, {
|
|
181
181
|
fixed: cfg.portExplicit,
|
|
@@ -194,11 +194,17 @@ async function startForeground(cfg) {
|
|
|
194
194
|
createStack(devStack(ready));
|
|
195
195
|
if (port !== cfg.port) note(`Port ${cfg.port} is in use — serving on ${port} instead.`);
|
|
196
196
|
if (dbPort !== cfg.dbPort) note(`Database port ${cfg.dbPort} is in use — using ${dbPort} instead.`);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
197
|
+
return ready;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* After a boot, sync the fresh credentials (or the current LAN URL) into `.env` and the plugin, print
|
|
201
|
+
* the connection summary, and print the timed ready line. `reloaded` swaps the wording and drops the
|
|
202
|
+
* one-time Ctrl+C hint. `start` is when the boot began, so the timing spans the whole reboot including
|
|
203
|
+
* the spinner. The `.env` writes here are why the caller pauses the reload watcher around a reboot.
|
|
204
|
+
*/
|
|
205
|
+
async function report(cfg, creds, reloaded, start) {
|
|
200
206
|
if (creds.appPassword) {
|
|
201
|
-
const env = updateWpEnv(
|
|
207
|
+
const env = updateWpEnv(cfg, creds);
|
|
202
208
|
note("Updated .env with the new WordPress credentials");
|
|
203
209
|
if (env) {
|
|
204
210
|
const sync = await syncSiteSettings({
|
|
@@ -212,76 +218,155 @@ async function startForeground(cfg) {
|
|
|
212
218
|
});
|
|
213
219
|
if (!sync.ok) note(`Could not sync the site settings to WordPress (${sync.error}) — make sure the kizlo plugin is active, then set them from the Kizlo settings.`);
|
|
214
220
|
}
|
|
215
|
-
} else if (
|
|
221
|
+
} else if (syncLocalUrl(cfg, creds.url)) note("Updated .env WordPress URL to the current network address — restart your app to pick it up");
|
|
216
222
|
printSummary(creds);
|
|
217
223
|
const { green, dim, bold, reset } = palette();
|
|
218
224
|
const ms = Date.now() - start;
|
|
219
225
|
const took = ms < 1e3 ? `${ms}ms` : `${(ms / 1e3).toFixed(1)}s`;
|
|
220
|
-
process.stdout.write(`\n ${dim}Press ${reset}${bold}Ctrl+C${reset}${dim} (or close the terminal) to stop
|
|
221
|
-
process.stdout.write(`\n ${green}✓${reset} Ready in ${took}\n\n`);
|
|
222
|
-
|
|
223
|
-
|
|
226
|
+
if (!reloaded) process.stdout.write(`\n ${dim}Press ${reset}${bold}Ctrl+C${reset}${dim} (or close the terminal) to stop local WordPress${reset}\n`);
|
|
227
|
+
process.stdout.write(`\n ${green}✓${reset} ${reloaded ? "Reloaded" : "Ready"} in ${took}\n\n`);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Boot local WordPress for an already-prepared `cfg` (ports resolved, teardown armed) behind a spinner,
|
|
231
|
+
* then report. The first-boot path only — reboots go through {@link rebootStack}, which also folds the
|
|
232
|
+
* prepare step under the spinner.
|
|
233
|
+
*/
|
|
234
|
+
async function bootAndReport(cfg) {
|
|
235
|
+
const start = Date.now();
|
|
236
|
+
await report(cfg, await withSpinner("Starting local WordPress", () => bootstrapDev(cfg)), false, start);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Reboot the whole stack in place after a config/env change: re-resolve the config, recreate the
|
|
240
|
+
* containers, and boot WordPress — all behind a single spinner labelled with the file that changed, so
|
|
241
|
+
* there's no loaderless gap between detecting the change and the boot. Teardown is already armed from
|
|
242
|
+
* the first boot, so this never re-arms. Returns the freshly resolved config (ports may have moved) so
|
|
243
|
+
* the caller can re-target its watchers.
|
|
244
|
+
*/
|
|
245
|
+
async function rebootStack(cwd, label) {
|
|
246
|
+
const start = Date.now();
|
|
247
|
+
const { ready, creds } = await withSpinner(label, async () => {
|
|
248
|
+
const ready$1 = await prepareStack(await resolveDevConfig(cwd));
|
|
249
|
+
return {
|
|
250
|
+
ready: ready$1,
|
|
251
|
+
creds: await bootstrapDev(ready$1)
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
await report(ready, creds, true, start);
|
|
255
|
+
return ready;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Boot local WordPress and run in the foreground until exit — the path behind bare `kizlo dev`. Arms
|
|
259
|
+
* teardown first (so a mid-startup cancel still stops partial containers), boots and prints the
|
|
260
|
+
* summary, then parks. While parked it watches `.env` and `kizlo.config.*`: a change reboots the whole
|
|
261
|
+
* stack in place so a new port, connection, or fixture takes effect without rerunning the command. The
|
|
262
|
+
* reboot runs in the same process — the watchdog and session keep watching this PID throughout — and is
|
|
263
|
+
* guarded so the credential/URL writes it makes to `.env` don't trigger another reboot. A referenced
|
|
264
|
+
* timer holds the event loop open — an unresolved promise alone would not, so without it Node would
|
|
265
|
+
* empty its loop and exit straight after printing.
|
|
266
|
+
*/
|
|
267
|
+
async function startForeground(cfg) {
|
|
268
|
+
const cwd = process.cwd();
|
|
269
|
+
let ready = await prepareStack(cfg);
|
|
270
|
+
armForegroundTeardown(ready);
|
|
271
|
+
await bootAndReport(ready);
|
|
272
|
+
let stopContract = await startWatcher(ready.configDir);
|
|
273
|
+
let reloading = false;
|
|
274
|
+
const reload = async (changed) => {
|
|
275
|
+
if (reloading) return;
|
|
276
|
+
reloading = true;
|
|
277
|
+
try {
|
|
278
|
+
stopContract?.();
|
|
279
|
+
ready = await rebootStack(cwd, `${changed} changed — restarting the session`);
|
|
280
|
+
stopContract = await startWatcher(ready.configDir);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
log.error("Failed to reload the dev session:", error);
|
|
283
|
+
} finally {
|
|
284
|
+
setTimeout(() => {
|
|
285
|
+
reloading = false;
|
|
286
|
+
}, 500);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
const stopReload = watchReload(ready.configDir, (changed) => void reload(changed));
|
|
290
|
+
process.on("exit", () => {
|
|
291
|
+
stopContract?.();
|
|
292
|
+
stopReload();
|
|
293
|
+
});
|
|
224
294
|
setInterval(() => {}, 1 << 30);
|
|
225
295
|
await new Promise(() => {});
|
|
226
296
|
}
|
|
227
297
|
/**
|
|
228
|
-
* Run the contract watcher in the foreground until exit — the path bare `kizlo dev` takes when
|
|
229
|
-
*
|
|
230
|
-
* the server files and regenerates on save.
|
|
231
|
-
* the
|
|
298
|
+
* Run the contract watcher in the foreground until exit — the path bare `kizlo dev` takes when local
|
|
299
|
+
* WordPress isn't configured (a project pointing at its own WordPress). Generates once, then watches
|
|
300
|
+
* the server files and regenerates on save. It also watches `.env` and `kizlo.config.*` and restarts
|
|
301
|
+
* the watcher on a change, so a new server dir or env value is picked up the same way the local path
|
|
302
|
+
* reboots its stack. Returns immediately when another watcher already holds the lock; otherwise the
|
|
303
|
+
* persistent watcher keeps the process alive on its own.
|
|
232
304
|
*/
|
|
233
305
|
async function watchOnly(cwd) {
|
|
234
|
-
|
|
306
|
+
let stop = await startWatcher(cwd);
|
|
235
307
|
if (!stop) return;
|
|
236
|
-
|
|
308
|
+
let reloading = false;
|
|
309
|
+
const reload = async () => {
|
|
310
|
+
if (reloading) return;
|
|
311
|
+
reloading = true;
|
|
312
|
+
try {
|
|
313
|
+
stop?.();
|
|
314
|
+
stop = await startWatcher(cwd);
|
|
315
|
+
} finally {
|
|
316
|
+
setTimeout(() => {
|
|
317
|
+
reloading = false;
|
|
318
|
+
}, 300);
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
const stopReload = watchReload(findConfigDir(cwd), () => void reload());
|
|
322
|
+
const shutdown = () => {
|
|
323
|
+
stop?.();
|
|
324
|
+
stopReload();
|
|
325
|
+
};
|
|
326
|
+
process.on("exit", shutdown);
|
|
237
327
|
for (const signal of [
|
|
238
328
|
"SIGINT",
|
|
239
329
|
"SIGTERM",
|
|
240
330
|
"SIGHUP"
|
|
241
331
|
]) process.on(signal, () => {
|
|
242
|
-
|
|
332
|
+
shutdown();
|
|
243
333
|
process.exit(0);
|
|
244
334
|
});
|
|
245
335
|
}
|
|
246
336
|
/**
|
|
247
|
-
* Start (or resume)
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
337
|
+
* Start (or resume) local WordPress. Backs bare `kizlo dev`. Always runs in the foreground and stops
|
|
338
|
+
* it on exit, so it never outlives the session — the subcommands (`stop`/`reset`) manage everything
|
|
339
|
+
* else. Without local WordPress configured there's nothing to boot, so it runs the contract watcher
|
|
340
|
+
* alone.
|
|
251
341
|
*/
|
|
252
342
|
async function bringUp() {
|
|
253
343
|
const cwd = process.cwd();
|
|
254
|
-
if (!await
|
|
344
|
+
if (!await usesLocalWordPress(cwd)) {
|
|
345
|
+
note("This project doesn't run local WordPress — running the contract watcher only. Set `dev.local` in kizlo.config.ts to add it.");
|
|
255
346
|
await watchOnly(cwd);
|
|
256
347
|
return;
|
|
257
348
|
}
|
|
349
|
+
const status = await dockerStatus();
|
|
350
|
+
if (status !== "running") {
|
|
351
|
+
note(dockerHint(status));
|
|
352
|
+
process.exit(1);
|
|
353
|
+
}
|
|
258
354
|
const reaped = await reapOrphans();
|
|
259
|
-
if (reaped.length) note(`Stopped ${reaped.length} orphaned
|
|
355
|
+
if (reaped.length) note(`Stopped ${reaped.length} orphaned local WordPress${reaped.length === 1 ? "" : "s"}: ${reaped.join(", ")}`);
|
|
260
356
|
const cfg = await resolveDevConfig(cwd);
|
|
261
|
-
|
|
357
|
+
ensureGitignored(cfg.configDir, ".kizlo/");
|
|
262
358
|
await startForeground(cfg);
|
|
263
359
|
}
|
|
264
360
|
const subCommands = {
|
|
265
361
|
stop: defineCommand({
|
|
266
362
|
meta: {
|
|
267
363
|
name: "stop",
|
|
268
|
-
description: "Stop
|
|
269
|
-
},
|
|
270
|
-
async run() {
|
|
271
|
-
if (!await requireDevStack(process.cwd())) return;
|
|
272
|
-
const { stack } = await resolve$1(process.cwd());
|
|
273
|
-
await withSpinner("Stopping WordPress dev stack", () => stack.composeStop(), "Stack stopped (volumes kept)");
|
|
274
|
-
}
|
|
275
|
-
}),
|
|
276
|
-
down: defineCommand({
|
|
277
|
-
meta: {
|
|
278
|
-
name: "down",
|
|
279
|
-
description: "Stop and remove the dev stack containers (keeps the database and files)"
|
|
364
|
+
description: "Stop local WordPress, keeping the database volume"
|
|
280
365
|
},
|
|
281
366
|
async run() {
|
|
282
|
-
if (!await
|
|
367
|
+
if (!await requireLocalWordPress(process.cwd())) return;
|
|
283
368
|
const { stack } = await resolve$1(process.cwd());
|
|
284
|
-
await withSpinner("
|
|
369
|
+
await withSpinner("Stopping local WordPress", () => stack.composeStop(), "Local WordPress stopped (volumes kept)");
|
|
285
370
|
}
|
|
286
371
|
}),
|
|
287
372
|
reset: defineCommand({
|
|
@@ -290,21 +375,21 @@ const subCommands = {
|
|
|
290
375
|
description: "Wipe the database and the install folder so the next `kizlo dev` rebuilds fresh"
|
|
291
376
|
},
|
|
292
377
|
async run() {
|
|
293
|
-
if (!await
|
|
378
|
+
if (!await requireLocalWordPress(process.cwd())) return;
|
|
294
379
|
const { cfg, stack } = await resolve$1(process.cwd());
|
|
295
|
-
await withSpinner("Wiping WordPress
|
|
380
|
+
await withSpinner("Wiping local WordPress", () => stack.composeDown({ volumes: true }), "Local WordPress reset successfully");
|
|
296
381
|
rmSync(cfg.wordpressDir, {
|
|
297
382
|
recursive: true,
|
|
298
383
|
force: true
|
|
299
384
|
});
|
|
300
|
-
note("Run `kizlo dev` to rebuild
|
|
385
|
+
note("Run `kizlo dev` to rebuild fresh.");
|
|
301
386
|
}
|
|
302
387
|
})
|
|
303
388
|
};
|
|
304
389
|
const dev = defineCommand({
|
|
305
390
|
meta: {
|
|
306
391
|
name: "dev",
|
|
307
|
-
description: "Run
|
|
392
|
+
description: "Run local WordPress and the contract watcher (stop | reset)"
|
|
308
393
|
},
|
|
309
394
|
subCommands,
|
|
310
395
|
run: groupDefault(Object.keys(subCommands), bringUp)
|