diff --git a/manifest.ts b/manifest.ts index 147a071..1b499d5 100644 --- a/manifest.ts +++ b/manifest.ts @@ -35,7 +35,7 @@ import type { PluginManifest } from '@@/plugins/manifest'; */ export const manifest: PluginManifest = { publisher: 'officerdev', - version: '2026.08.29.11', + version: '2026.08.29.12', platform: '>=1.0.0', label: 'Fofos', diff --git a/web/WebsiteCheckout.tsx b/web/WebsiteCheckout.tsx index 03df88e..4497fb5 100644 --- a/web/WebsiteCheckout.tsx +++ b/web/WebsiteCheckout.tsx @@ -3,6 +3,7 @@ import { CircleAlert, CircleCheck, CircleDashed, DownloadCloud, Loader2, Refresh import { useClient } from 'hooks/useClient'; import { Button } from '@/components/ui/button'; import { readableError } from './errors'; +import { useFlash } from './useFlash'; /** * The website checkout under the root location: is it there, clone it, update it. @@ -18,6 +19,15 @@ import { readableError } from './errors'; * "Permission denied (publickey)" says exactly what is wrong. Anything this could write in its place * would be a guess at which of a dozen causes it was, and the guess is what sends somebody looking in * the wrong direction. + * + * ── The console closes itself on success, and never on failure ── + * + * A successful clone or update is worth WATCHING and not worth keeping: "74 packages installed" has + * been read by the time it finishes, and left on screen it becomes furniture that outlives its own + * truth — still sitting there after the root has been changed underneath it. + * + * A failure is the opposite. It stays until something else happens, because it is the only copy of + * why, and a transcript that scrolled past is one somebody has to reproduce to read. */ type Status = { @@ -42,6 +52,7 @@ export const WebsiteCheckout = ({ rootPath }: { rootPath: string }) => { const [busy, setBusy] = useState<'clone' | 'update' | null>(null); const [output, setOutput] = useState(null); const [failed, setFailed] = useState(false); + const [showing, show] = useFlash(); const load = useCallback(async () => { try { @@ -68,6 +79,9 @@ export const WebsiteCheckout = ({ rootPath }: { rootPath: string }) => { setStatus(result.status); setOutput(result.output || null); setFailed(!result.ok); + // Only on the way out. A failure has no timer at all rather than a long one — nothing should be + // able to take it off the screen except the next attempt. + if (result.ok) show(); } catch (failure) { // A 400 carries git's own words in the body; `readableError` surfaces them. setOutput(readableError(failure)); @@ -129,15 +143,12 @@ export const WebsiteCheckout = ({ rootPath }: { rootPath: string }) => { - {/* git's own words, in git's own shape. Scrolled rather than truncated — the useful line of a - clone failure is usually the last one. */} - {output && ( -
-          {output}
+      {/* git's own words, in git's own shape — a console, so it looks like the thing it is quoting
+          rather than like a paragraph of the form. Scrolled, not truncated: the useful line of a
+          failure is usually the last one. */}
+      {output && (failed || showing) && (
+        
+          {output}
         
)}