@rubytech/create-realagent 1.0.669 → 1.0.671
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/index.js +120 -10
- package/package.json +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +36 -0
- package/payload/server/public/assets/graph-bX0xIBhR.js +49 -0
- package/payload/server/public/graph.html +1 -1
- package/payload/server/public/assets/graph-BFLumOll.js +0 -49
package/dist/index.js
CHANGED
|
@@ -207,14 +207,112 @@ function canSudo() {
|
|
|
207
207
|
return result.status === 0;
|
|
208
208
|
}
|
|
209
209
|
// Task 634 — verified-not-asserted apt-dep reconciliation.
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
// (
|
|
210
|
+
// Task 637 — resolve package-name aliases before probing dpkg, so the
|
|
211
|
+
// post-install check no longer false-negatives when apt resolves a virtual
|
|
212
|
+
// name (e.g. Noble's `chromium` → `chromium-browser`).
|
|
213
|
+
// Virtual-package aliases applied when `apt-cache policy <pkg>` returns
|
|
214
|
+
// `Candidate: (none)`. Keyed by apt-level alias, valued by the real .deb
|
|
215
|
+
// name actually recorded in dpkg after install. Scoped per distro family
|
|
216
|
+
// by the caller in `resolveAptName`. Add entries here if a new alias class
|
|
217
|
+
// surfaces — no code surgery needed.
|
|
218
|
+
const UBUNTU_ALIASES = {
|
|
219
|
+
// Noble ships `chromium` as a virtual package that resolves to
|
|
220
|
+
// `chromium-browser`, which is itself a transitional stub delegating to
|
|
221
|
+
// the snap. The runtime binary at /usr/bin/chromium is a snap symlink;
|
|
222
|
+
// dpkg records `chromium-browser` post-install, never `chromium`.
|
|
223
|
+
chromium: "chromium-browser",
|
|
224
|
+
};
|
|
225
|
+
function readOsRelease() {
|
|
226
|
+
try {
|
|
227
|
+
const raw = readFileSync("/etc/os-release", "utf-8");
|
|
228
|
+
const out = {};
|
|
229
|
+
for (const line of raw.split("\n")) {
|
|
230
|
+
const m = line.match(/^([A-Z_]+)=(.*)$/);
|
|
231
|
+
if (m)
|
|
232
|
+
out[m[1]] = m[2].replace(/^"|"$/g, "");
|
|
233
|
+
}
|
|
234
|
+
return out;
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
return {};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function isUbuntuLike() {
|
|
241
|
+
const os = readOsRelease();
|
|
242
|
+
if (os.ID === "ubuntu")
|
|
243
|
+
return true;
|
|
244
|
+
const likes = (os.ID_LIKE ?? "").split(/\s+/);
|
|
245
|
+
return likes.includes("ubuntu");
|
|
246
|
+
}
|
|
247
|
+
/** Summarise `apt-cache policy` output for diagnostics — one token per package. */
|
|
248
|
+
function aptCachePolicySummary(pkg) {
|
|
249
|
+
const r = spawnSync("apt-cache", ["policy", pkg], { stdio: "pipe", encoding: "utf-8", timeout: 5_000 });
|
|
250
|
+
if (r.status !== 0)
|
|
251
|
+
return "policy-spawn-failed";
|
|
252
|
+
const out = r.stdout ?? "";
|
|
253
|
+
const cand = out.match(/Candidate:\s*(\S+)/);
|
|
254
|
+
if (!cand)
|
|
255
|
+
return "no-candidate-line";
|
|
256
|
+
return cand[1] === "(none)" ? "candidate-none" : `candidate=${cand[1]}`;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Task 637 — map an apt-level package name to the concrete name dpkg will
|
|
260
|
+
* record after install. Resolution order:
|
|
261
|
+
* 1. `dpkg -s pkg` exits 0 → name is concrete and installed; return pkg.
|
|
262
|
+
* 2. `apt-cache policy pkg` reports a real Candidate → concrete-but-missing;
|
|
263
|
+
* return pkg (apt-get install + post-check will use the same name).
|
|
264
|
+
* 3. `apt-cache policy pkg` reports `Candidate: (none)` and `pkg` is in
|
|
265
|
+
* UBUNTU_ALIASES on an Ubuntu-like host → return the alias. Log the
|
|
266
|
+
* resolution so the install log answers "what did apt resolve this to?".
|
|
267
|
+
* 4. Otherwise return pkg unchanged — the post-check will throw loudly,
|
|
268
|
+
* preserving Task 634's fail-loud contract for genuinely missing packages.
|
|
269
|
+
*/
|
|
270
|
+
function resolveAptName(pkg) {
|
|
271
|
+
const dpkg = spawnSync("dpkg", ["-s", pkg], { stdio: "pipe", timeout: 5_000 });
|
|
272
|
+
if (dpkg.status === 0)
|
|
273
|
+
return pkg;
|
|
274
|
+
const policy = spawnSync("apt-cache", ["policy", pkg], {
|
|
275
|
+
stdio: "pipe", encoding: "utf-8", timeout: 5_000,
|
|
276
|
+
});
|
|
277
|
+
if (policy.status === 0) {
|
|
278
|
+
const cand = (policy.stdout ?? "").match(/Candidate:\s*(\S+)/);
|
|
279
|
+
if (cand && cand[1] !== "(none)")
|
|
280
|
+
return pkg;
|
|
281
|
+
}
|
|
282
|
+
if (isUbuntuLike() && Object.prototype.hasOwnProperty.call(UBUNTU_ALIASES, pkg)) {
|
|
283
|
+
const alias = UBUNTU_ALIASES[pkg];
|
|
284
|
+
const os = readOsRelease();
|
|
285
|
+
const distro = `${os.ID ?? "unknown"}-${os.VERSION_CODENAME ?? "unknown"}`;
|
|
286
|
+
logFile(` apt-resolve ${pkg} → ${alias} (reason=candidate-none, distro=${distro})`);
|
|
287
|
+
return alias;
|
|
288
|
+
}
|
|
289
|
+
return pkg;
|
|
290
|
+
}
|
|
291
|
+
/** Probe runtime binary presence on PATH (independent of dpkg-recorded state). */
|
|
292
|
+
function commandVPath(pkg) {
|
|
293
|
+
const r = spawnSync("which", [pkg], { stdio: "pipe", encoding: "utf-8", timeout: 5_000 });
|
|
294
|
+
return r.status === 0 ? (r.stdout ?? "").trim() || "missing" : "missing";
|
|
295
|
+
}
|
|
296
|
+
/** Probe snap-recorded state for a name (snap lives outside dpkg). */
|
|
297
|
+
function snapStatus(pkg) {
|
|
298
|
+
const r = spawnSync("snap", ["list", pkg], { stdio: "pipe", encoding: "utf-8", timeout: 5_000 });
|
|
299
|
+
if (r.status !== 0)
|
|
300
|
+
return "none";
|
|
301
|
+
const line = (r.stdout ?? "").split("\n").find((l) => l.startsWith(pkg));
|
|
302
|
+
return line ? line.split(/\s+/).slice(0, 2).join(" ") : "none";
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Returns the subset of `pkgs` that are not currently installed, after
|
|
306
|
+
* alias resolution. Uses `dpkg -s <resolved>` per package (exit 0 = installed,
|
|
307
|
+
* any non-zero = missing) so we never parse dpkg's prose output for control
|
|
308
|
+
* flow (feedback_no_stdout_parsing_for_control_flow.md). The operator-facing
|
|
309
|
+
* name stays the original `pkg` — the resolution is logged but not renamed
|
|
310
|
+
* in the returned list, so diagnostics match what the installer declared.
|
|
311
|
+
*/
|
|
215
312
|
function pkgsMissing(pkgs) {
|
|
216
313
|
return pkgs.filter((p) => {
|
|
217
|
-
const
|
|
314
|
+
const resolved = resolveAptName(p);
|
|
315
|
+
const r = spawnSync("dpkg", ["-s", resolved], { stdio: "pipe", timeout: 5_000 });
|
|
218
316
|
return r.status !== 0;
|
|
219
317
|
});
|
|
220
318
|
}
|
|
@@ -224,13 +322,25 @@ function pkgsMissing(pkgs) {
|
|
|
224
322
|
* partial-failure class where `apt-get install` returns 0 but a package did
|
|
225
323
|
* not actually install — silent regressions that would otherwise only
|
|
226
324
|
* surface at runtime when the binary is missing.
|
|
325
|
+
*
|
|
326
|
+
* Resolves each package through `resolveAptName` before both the install
|
|
327
|
+
* command and the post-check, so alias packages (Task 637) pass through
|
|
328
|
+
* cleanly on distros where the apt-level name differs from the dpkg-recorded
|
|
329
|
+
* name (e.g. Noble's chromium → chromium-browser). Resolution is computed
|
|
330
|
+
* once per package and reused across install, post-check, and error
|
|
331
|
+
* diagnostics — three spawnSync chains per package, not nine on failure.
|
|
227
332
|
*/
|
|
228
333
|
function installAptGroup(label, pkgs) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
334
|
+
const pairs = pkgs.map((original) => ({ original, resolved: resolveAptName(original) }));
|
|
335
|
+
logFile(` apt install (${label}): ${pairs.map((x) => x.resolved).join(" ")}`);
|
|
336
|
+
shell("apt-get", ["install", "-y", ...pairs.map((x) => x.resolved)], { sudo: true });
|
|
337
|
+
const stillMissing = pairs.filter(({ resolved }) => {
|
|
338
|
+
const r = spawnSync("dpkg", ["-s", resolved], { stdio: "pipe", timeout: 5_000 });
|
|
339
|
+
return r.status !== 0;
|
|
340
|
+
});
|
|
232
341
|
if (stillMissing.length > 0) {
|
|
233
|
-
|
|
342
|
+
const diag = stillMissing.map(({ original, resolved }) => `${original} (resolved-name=${resolved}, apt-cache-policy=${aptCachePolicySummary(original)}, command-v=${commandVPath(original)}, snap-status=${snapStatus(resolved)})`).join("; ");
|
|
343
|
+
throw new Error(`apt-get install (${label}) returned 0 but packages are still not installed per dpkg -s: ${diag}`);
|
|
234
344
|
}
|
|
235
345
|
}
|
|
236
346
|
// ---------------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -207,6 +207,42 @@ which xdotool # should return /usr/bin/xdotool
|
|
|
207
207
|
|
|
208
208
|
---
|
|
209
209
|
|
|
210
|
+
## Installer aborts on Ubuntu 24.04 with `dpkg -s: chromium`
|
|
211
|
+
|
|
212
|
+
**Symptom:** On a fresh (or re-run) `npx -y @rubytech/create-maxy@latest` on an Ubuntu 24.04 Noble laptop/desktop, step 1/12 aborts:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
[1/12] System dependencies and network...
|
|
216
|
+
Missing apt deps (1): chromium
|
|
217
|
+
apt install (VNC stack): tigervnc-standalone-server python3-websockify novnc xdg-utils chromium xterm xdotool
|
|
218
|
+
> sudo apt-get install -y ... chromium ...
|
|
219
|
+
OK in 0.3s
|
|
220
|
+
[ERROR] Setup failed: apt-get install (VNC stack) returned 0 but packages are still not installed per dpkg -s: chromium
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Directly probing the device shows `dpkg -s chromium` non-zero, `apt-cache policy chromium` reports `Candidate: (none)`, but `/usr/bin/chromium` exists and works, and `snap list chromium` shows the snap is installed.
|
|
224
|
+
|
|
225
|
+
**What it means:** You are on a **pre-637 installer**. On Noble, `chromium` is a virtual package aliasing to `chromium-browser` — `apt-get install chromium` succeeds silently but nothing named `chromium` ever lands in dpkg's state DB. Task 634's post-install probe (correctly) notices the discrepancy and aborts. Task 637 added alias resolution (`chromium` → `chromium-browser`) so the probe matches the dpkg-recorded name and passes.
|
|
226
|
+
|
|
227
|
+
**Fix:** Upgrade to a post-637 version of `@rubytech/create-maxy`:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
npx -y @rubytech/create-maxy@latest
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**Manual bypass** (if you must install before 637 publishes, or if you're on a restricted shell): pre-install the real .deb name and re-run the installer.
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
sudo apt-get install -y chromium-browser
|
|
237
|
+
npx -y @rubytech/create-maxy@latest
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The installer's resolver will then see `dpkg -s chromium-browser` exit 0 for the alias target, filter `chromium` out of the missing set, and skip the apt-install branch entirely. Raspberry Pi OS (Debian 12 Bookworm) is unaffected — `chromium` IS a concrete .deb on Bookworm.
|
|
241
|
+
|
|
242
|
+
**Deeper diagnostic**: post-637 installer logs carry the full classification in the error message itself — `(resolved-name=<name>, apt-cache-policy=<summary>, command-v=<path>, snap-status=<summary>)`. If you see that longer form and still fail, the apt state itself is inconsistent (snap removed, `chromium-browser` uninstalled after previous install) — repair with `sudo apt-get install --reinstall -y chromium-browser`.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
210
246
|
## Terminal iframe renders black and cursor vanishes over the canvas
|
|
211
247
|
|
|
212
248
|
**Symptom:** Header-menu Terminal click appears to succeed — no error toast, overlay opens — but the iframe renders uniformly black, keystrokes do not reach any shell, and the mouse cursor disappears the moment it enters the iframe (visible elsewhere in the page).
|