diff --git a/package.json b/package.json index 9607ff1ae..32d723456 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,8 @@ "check:evidence-integrity": "tsx scripts/check-evidence-integrity.ts", "check:maestro-release-gate-events": "tsx scripts/check-maestro-release-gate-events.ts", "check:scenario-replay-gate": "node scripts/run-scenario-replay-gate.mjs", - "check:workflow-footguns": "node scripts/check-workflow-footguns.mjs", + "check:removed-ts-tui": "node ./scripts/check-removed-ts-tui-refs.mjs", + "check:workflow-footguns": "node scripts/check-workflow-footguns.mjs && npm run check:removed-ts-tui", "check:test-skip-hygiene": "node scripts/check-test-skip-hygiene.mjs", "check:test-timing-wait-hygiene": "node scripts/check-test-timing-wait-hygiene.mjs", "check:atomic-write-hygiene": "node scripts/check-atomic-write-hygiene.mjs", diff --git a/packages/tui-rs/src/app/command_handlers.rs b/packages/tui-rs/src/app/command_handlers.rs index d849c6bb9..5ce01ce22 100644 --- a/packages/tui-rs/src/app/command_handlers.rs +++ b/packages/tui-rs/src/app/command_handlers.rs @@ -1213,7 +1213,7 @@ impl App { } A2aAction::Accept { code } => { self.state.add_system_message(format!( - "A2A pairing code captured ({} chars). Run `maestro a2a accept ` or use the TypeScript TUI `/a2a accept ` to persist it in the shared registry.", + "A2A pairing code captured ({} chars). Run `maestro a2a accept ` Persist it with `/a2a accept ` in this TUI, or `maestro a2a accept ` from the CLI.", code.len() )); } diff --git a/scripts/check-removed-ts-tui-refs.mjs b/scripts/check-removed-ts-tui-refs.mjs new file mode 100755 index 000000000..e33b5904a --- /dev/null +++ b/scripts/check-removed-ts-tui-refs.mjs @@ -0,0 +1,76 @@ +#!/usr/bin/env node +/** + * Fail if the removed TypeScript TUI reappears in live code paths or nx graph. + */ +import { readdirSync, readFileSync, statSync } from "node:fs"; +import { join } from "node:path"; + +const root = process.cwd(); +const bannedExact = ["@evalops/tui", "packages/tui/", "src/cli-tui/", "../tui/"]; +const bannedProjectNames = new Set(["tui"]); + +function walk(dir, out = []) { + for (const name of readdirSync(dir)) { + if (name === "node_modules" || name === "target" || name === "dist" || name === ".git") continue; + const p = join(dir, name); + const st = statSync(p); + if (st.isDirectory()) walk(p, out); + else out.push(p); + } + return out; +} + +const roots = ["packages", "src", "scripts", ".github", "project.json", "package.json", "nx.json"].map((r) => join(root, r)); +const files = []; +for (const r of roots) { + try { + const st = statSync(r); + if (st.isDirectory()) walk(r, files); + else files.push(r); + } catch { + // missing ok + } +} + +const offenders = []; +for (const file of files) { + if (!/\.(json|yml|yaml|ts|tsx|js|mjs|cjs|toml|rs|Dockerfile|dockerfile)$/i.test(file) && !file.endsWith("Dockerfile")) continue; + if (file.includes("/test/scripts/install-smoke") || file.includes("/test/scripts/smoke-published") || file.includes("/test/scripts/verify-published")) continue; + if (file.includes("/test/testing/auto-verify")) continue; + if (file.endsWith("check-removed-ts-tui-refs.mjs")) continue; + if (file.includes("prepare-public-release-mirror.mjs")) continue; + if (file.includes("check-public-mirror")) continue; + if (file.includes("sync-public-companion")) continue; + if (file.includes("sync-release-mirror")) continue; + let text; + try { + text = readFileSync(file, "utf8"); + } catch { + continue; + } + for (const b of bannedExact) { + if (!text.includes(b)) continue; + if (b === "packages/tui/") { + const re = /packages\/tui(?!-rs)/g; + if (!re.test(text)) continue; + } + offenders.push(`${file}: contains ${b}`); + } + if (file.endsWith("project.json")) { + try { + const j = JSON.parse(text); + for (const d of j.implicitDependencies || []) { + if (bannedProjectNames.has(d)) offenders.push(`${file}: implicitDependencies includes removed project '${d}'`); + } + } catch { + // ignore + } + } +} + +if (offenders.length) { + console.error("Removed TypeScript TUI references found:"); + for (const o of offenders) console.error(" -", o); + process.exit(1); +} +console.log("check-removed-ts-tui-refs: ok"); diff --git a/scripts/prepare-public-release-mirror.mjs b/scripts/prepare-public-release-mirror.mjs index 81fd9449b..f5389310e 100644 --- a/scripts/prepare-public-release-mirror.mjs +++ b/scripts/prepare-public-release-mirror.mjs @@ -384,6 +384,27 @@ function applyMirrorPlan(sourceRoot, targetRoot, plan) { for (const relativePath of plan.deletedPaths) { rmSync(resolve(targetRoot, relativePath), { force: true }); } + + // File deletes leave empty parent directories (e.g. packages/tui/, src/cli-tui/). + // Prune empty dirs bottom-up so the public tree does not retain hollow shells. + const dirs = new Set(); + for (const relativePath of plan.deletedPaths) { + let dir = dirname(resolve(targetRoot, relativePath)); + const rootResolved = resolve(targetRoot); + while (dir.startsWith(rootResolved) && dir !== rootResolved) { + dirs.add(dir); + dir = dirname(dir); + } + } + for (const dir of [...dirs].sort((a, b) => b.length - a.length)) { + try { + if (existsSync(dir) && readdirSync(dir).length === 0) { + rmSync(dir, { force: true }); + } + } catch { + // ignore races / non-empty + } + } } function writeReport(path, report) {