show what the commands are actually saying
Install, uninstall and purge narrated what the platform was doing and hid what it was running. Every spawn captured stdout and stderr, held them, and surfaced the last 600 characters only if the exit code was non-zero. That is enough to explain a crash and useless for the two things people want while watching an install: knowing a slow step is still moving, and seeing the warning a command prints on its way to exiting 0. The second is not hypothetical — `db:push` reported success on a machine where it created no tables. Its output was captured, discarded because the exit code was fine, and the failure surfaced minutes later as 42P01 in a sidecar log. Whatever drizzle said about that push, nobody ever read it. `runLogged` streams both pipes as they arrive, so they interleave the way they do in a terminal. Following only stdout would have been silent for exactly the commands worth watching: git writes everything to stderr, drizzle-kit writes progress there and results to stdout. Two pieces of noise control, because a log nobody can read is not an improvement: `git clone` gets `--progress` instead of `--quiet` (git says nothing when it thinks it has no terminal, and that is the step where a slow link looks like a hang) with per-percent rewrites collapsed to the last fragment per chunk; and drizzle's spinner, which is eight lines saying the same thing with a different braille glyph, collapses to the first — otherwise "Changes applied" scrolls past underneath it. Steps and output share ONE ordered list rather than two. Their order relative to each other is the whole information: "which step was this output from" is the only question the log exists to answer. Output renders dimmer and indented under the step that produced it. Verified by running a real purge and reinstall: the clone's object counts, the barrel generation naming both plugins, drizzle's push, then "schema: applied in 2029ms (1 table verified)". tsgo clean, frontend builds, 873 pass / 7 fail unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import { publishAssets, unpublishAssets } from '../app-store/assets';
|
||||
import { refreshPluginMounts, snapshotPlugins } from './mount';
|
||||
import { generatePluginSchemas, pushSchema } from './schema';
|
||||
import { declaredTables, dropTables, existingTables } from './tables';
|
||||
import type { OnLog } from './run-logged';
|
||||
import { installDependencies, manualInstallHint, reportDependencies, stillMissing } from './os-deps';
|
||||
import { mountPrefix, type DiscoveredPlugin } from './manifest';
|
||||
|
||||
@@ -132,7 +133,12 @@ async function addToDock(userId: number, route: string): Promise<boolean> {
|
||||
* `enabled` is deliberately untouched on the upgrade path — re-installing something the owner had
|
||||
* switched off must not switch it back on.
|
||||
*/
|
||||
export async function installPlugin(appName: string, onStep?: OnStep, forUserId?: number): Promise<PluginActionResult> {
|
||||
export async function installPlugin(
|
||||
appName: string,
|
||||
onStep?: OnStep,
|
||||
forUserId?: number,
|
||||
onLog?: OnLog,
|
||||
): Promise<PluginActionResult> {
|
||||
const steps: string[] = [];
|
||||
|
||||
// FETCH FIRST, when the plugin is not here yet.
|
||||
@@ -147,7 +153,7 @@ export async function installPlugin(appName: string, onStep?: OnStep, forUserId?
|
||||
// as it was.
|
||||
let plugin = await findPlugin(appName);
|
||||
if (!plugin) {
|
||||
const fetched = await fetchPlugin(appName);
|
||||
const fetched = await fetchPlugin(appName, onLog);
|
||||
if (!fetched.ok) {
|
||||
return { ok: false, appName, steps, error: fetched.error ?? `cannot fetch "${appName}"` };
|
||||
}
|
||||
@@ -222,7 +228,7 @@ export async function installPlugin(appName: string, onStep?: OnStep, forUserId?
|
||||
const { plugins } = await discoverPlugins();
|
||||
generatePluginSchemas(plugins);
|
||||
|
||||
const pushed = await pushSchema();
|
||||
const pushed = await pushSchema(onLog);
|
||||
if (!pushed.ok) {
|
||||
return { ok: false, appName, steps, error: `schema push failed: ${pushed.output}` };
|
||||
}
|
||||
@@ -321,7 +327,7 @@ export async function installPlugin(appName: string, onStep?: OnStep, forUserId?
|
||||
* Keeps every table and row the plugin owns, and keeps the directory. Reinstalling is therefore a restore
|
||||
* rather than a fresh start, which is the whole reason not to drop anything here.
|
||||
*/
|
||||
export async function uninstallPlugin(appName: string, onStep?: OnStep): Promise<PluginActionResult> {
|
||||
export async function uninstallPlugin(appName: string, onStep?: OnStep, onLog?: OnLog): Promise<PluginActionResult> {
|
||||
const steps: string[] = [];
|
||||
const plugin = await findPlugin(appName);
|
||||
|
||||
@@ -372,7 +378,7 @@ export async function uninstallPlugin(appName: string, onStep?: OnStep): Promise
|
||||
* longer exists is exactly the failure that stopped a server booting on 2026-08-16. Leaving it stale here
|
||||
* would break the next `db:push` rather than this command.
|
||||
*/
|
||||
export async function purgePlugin(appName: string, onStep?: OnStep): Promise<PluginActionResult> {
|
||||
export async function purgePlugin(appName: string, onStep?: OnStep, onLog?: OnLog): Promise<PluginActionResult> {
|
||||
const steps: string[] = [];
|
||||
const plugin = await findPlugin(appName);
|
||||
if (!plugin) return { ok: false, appName, steps, error: `"${appName}" is not on this machine` };
|
||||
@@ -387,7 +393,7 @@ export async function purgePlugin(appName: string, onStep?: OnStep): Promise<Plu
|
||||
|
||||
// Stop it first. Dropping a table under a running sidecar gives it a 42P01 instead of a shutdown.
|
||||
if (await getPluginInstall(appName)) {
|
||||
const uninstalled = await uninstallPlugin(appName, onStep);
|
||||
const uninstalled = await uninstallPlugin(appName, onStep, onLog);
|
||||
if (!uninstalled.ok) return { ...uninstalled, steps: [...steps, ...uninstalled.steps] };
|
||||
steps.push(...uninstalled.steps);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user