youiyoux 0.1.9 → 0.1.10
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/chunks/{chunk-F33PKGES.js → chunk-3RP664IP.js} +1 -1
- package/dist/chunks/{chunk-E5OHZJBS.js → chunk-75DBKEAH.js} +278 -86
- package/dist/chunks/{chunk-Y4IBE6WS.js → chunk-OCZJ3JGH.js} +1 -1
- package/dist/chunks/{chunk-DCBF7QQY.js → chunk-T3KNPVQG.js} +1 -1
- package/dist/chunks/{chunk-3HON5Q5K.js → chunk-X2YYMHR4.js} +8 -2
- package/dist/chunks/{src-EUVBYTKY.js → src-6SNQVIZS.js} +2 -2
- package/dist/chunks/{src-YKPJ3PII.js → src-75ODGHE3.js} +2 -2
- package/dist/chunks/{src-M3OJMCUE.js → src-XTNHB65M.js} +1 -1
- package/dist/hub-previews.js +2 -2
- package/dist/hub-server.js +2 -2
- package/dist/hub-snapshot.js +1 -1
- package/dist/youi.js +2 -2
- package/dist/youiyoux.js +2 -2
- package/package.json +4 -4
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
vendoredPath,
|
|
54
54
|
whereUsed,
|
|
55
55
|
withFile
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-X2YYMHR4.js";
|
|
57
57
|
import {
|
|
58
58
|
escapingLinks,
|
|
59
59
|
within
|
|
@@ -137,6 +137,7 @@ import {
|
|
|
137
137
|
sha256,
|
|
138
138
|
shortHash,
|
|
139
139
|
toPosix,
|
|
140
|
+
unifiedDiff,
|
|
140
141
|
writeFileAtomic
|
|
141
142
|
} from "./chunk-DWYDHVLZ.js";
|
|
142
143
|
import {
|
|
@@ -147,8 +148,8 @@ import {
|
|
|
147
148
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
148
149
|
import { execFile as execFile5 } from "node:child_process";
|
|
149
150
|
import { existsSync as existsSync5 } from "node:fs";
|
|
150
|
-
import { appendFile as appendFile2, readFile as readFile10, rm as
|
|
151
|
-
import { basename as basename5, dirname as dirname13, join as
|
|
151
|
+
import { appendFile as appendFile2, readFile as readFile10, rm as rm7, rmdir as rmdir3 } from "node:fs/promises";
|
|
152
|
+
import { basename as basename5, dirname as dirname13, join as join26, relative as relative11, resolve as resolve15 } from "node:path";
|
|
152
153
|
import { parseArgs, promisify as promisify5 } from "node:util";
|
|
153
154
|
|
|
154
155
|
// ../cli/src/check.ts
|
|
@@ -166,7 +167,7 @@ import { join as join2, relative, resolve } from "node:path";
|
|
|
166
167
|
|
|
167
168
|
// ../cli/src/command.ts
|
|
168
169
|
var COMMAND = "youiyoux";
|
|
169
|
-
var SUBCOMMANDS = ["show", "where", "bom", "check", "baseline", "rules", "plan", "migrate", "init", "adopt", "status", "system", "sync", "link", "unlink", "scan", "watch", "hooks", "agents", "mcp", "ui", "library", "discover", "index", "report", "render", "screens", "requests", "detect", "build", "parity", "schema", "inventory", "gaps", "help"];
|
|
170
|
+
var SUBCOMMANDS = ["show", "where", "bom", "check", "baseline", "rules", "plan", "migrate", "upgrade", "init", "adopt", "status", "system", "sync", "link", "unlink", "scan", "watch", "hooks", "agents", "mcp", "ui", "library", "discover", "index", "report", "render", "screens", "requests", "detect", "build", "parity", "schema", "inventory", "gaps", "help"];
|
|
170
171
|
|
|
171
172
|
// ../cli/src/agents.ts
|
|
172
173
|
var import_yaml = __toESM(require_dist(), 1);
|
|
@@ -801,6 +802,7 @@ async function readLock(root) {
|
|
|
801
802
|
var Writer = class {
|
|
802
803
|
actions = [];
|
|
803
804
|
files = {};
|
|
805
|
+
contents = /* @__PURE__ */ new Map();
|
|
804
806
|
project;
|
|
805
807
|
options;
|
|
806
808
|
previous;
|
|
@@ -813,6 +815,7 @@ var Writer = class {
|
|
|
813
815
|
return join6(this.project.root, file);
|
|
814
816
|
}
|
|
815
817
|
async write(file, content) {
|
|
818
|
+
this.contents.set(file, content);
|
|
816
819
|
if (!this.options.dryRun) await writeFileAtomic(this.path(file), content);
|
|
817
820
|
}
|
|
818
821
|
record(action) {
|
|
@@ -985,7 +988,7 @@ async function syncProject(project2, options = {}) {
|
|
|
985
988
|
};
|
|
986
989
|
if (!options.dryRun) await writeFileAtomic(join6(project2.root, LOCK_FILE), `${JSON.stringify(lock, null, 2)}
|
|
987
990
|
`);
|
|
988
|
-
return { actions: writer.actions, lock, unknownTools: unknownToolMentions(project2) };
|
|
991
|
+
return { actions: writer.actions, lock, unknownTools: unknownToolMentions(project2), contents: writer.contents };
|
|
989
992
|
}
|
|
990
993
|
async function sameFile(a, b) {
|
|
991
994
|
const [x, y] = await Promise.all([realpath(a).catch(() => null), realpath(b).catch(() => null)]);
|
|
@@ -2106,7 +2109,7 @@ async function libraryLicence(id) {
|
|
|
2106
2109
|
}
|
|
2107
2110
|
}
|
|
2108
2111
|
async function startRuleEditor(options) {
|
|
2109
|
-
const { FileStore, RuleWorkflow, serveWorkflow } = await import("./src-
|
|
2112
|
+
const { FileStore, RuleWorkflow, serveWorkflow } = await import("./src-6SNQVIZS.js");
|
|
2110
2113
|
const projectRoot = resolve6(options.project);
|
|
2111
2114
|
const load2 = { ...options.config ? { configPath: resolve6(options.config) } : {}, ...options.design ? { designRoot: resolve6(options.design) } : {}, ...options.root ? { productRoot: resolve6(options.root) } : {} };
|
|
2112
2115
|
const project2 = await loadProject(projectRoot, load2);
|
|
@@ -2650,14 +2653,186 @@ async function extractSystem(project2, dir, options = {}) {
|
|
|
2650
2653
|
}
|
|
2651
2654
|
}
|
|
2652
2655
|
|
|
2656
|
+
// ../cli/src/upgrade.ts
|
|
2657
|
+
import { lstat as lstat2, rm as rm5 } from "node:fs/promises";
|
|
2658
|
+
import { join as join16 } from "node:path";
|
|
2659
|
+
var LOCK_FILE2 = "youi.lock.json";
|
|
2660
|
+
var WRITES = /* @__PURE__ */ new Set(["created", "updated", "merged", "adopted", "removed"]);
|
|
2661
|
+
function compareVersions(a, b) {
|
|
2662
|
+
const parse = (v) => {
|
|
2663
|
+
const [core = "", pre = ""] = v.replace(/^v/, "").split("-", 2);
|
|
2664
|
+
return [core.split(".").slice(0, 3).map((n) => Number(n) || 0), pre];
|
|
2665
|
+
};
|
|
2666
|
+
const [[x, xp], [y, yp]] = [parse(a), parse(b)];
|
|
2667
|
+
for (let i = 0; i < 3; i++) if ((x[i] ?? 0) !== (y[i] ?? 0)) return (x[i] ?? 0) - (y[i] ?? 0);
|
|
2668
|
+
if (xp === yp) return 0;
|
|
2669
|
+
return xp === "" ? 1 : yp === "" ? -1 : xp < yp ? -1 : 1;
|
|
2670
|
+
}
|
|
2671
|
+
function admits(range, version) {
|
|
2672
|
+
const parts = range.trim().split(/\s+/);
|
|
2673
|
+
const results = parts.map((part) => {
|
|
2674
|
+
if (part === "*" || part === "x") return true;
|
|
2675
|
+
const xr = /^v?(\d+)(?:\.(\d+|x))?(?:\.(x))?$/.exec(part);
|
|
2676
|
+
if (xr && (xr[2] === "x" || xr[3] === "x" || xr[2] === void 0)) {
|
|
2677
|
+
const [major, minor] = version.split(".").map(Number);
|
|
2678
|
+
return major === Number(xr[1]) && (xr[2] === void 0 || xr[2] === "x" || minor === Number(xr[2]));
|
|
2679
|
+
}
|
|
2680
|
+
const op = /^(\^|~|>=|<=|>|<|=)?v?(\d+\.\d+\.\d+(?:-[\w.]+)?)$/.exec(part);
|
|
2681
|
+
if (!op) return null;
|
|
2682
|
+
const [, kind = "=", base = ""] = op;
|
|
2683
|
+
const cmp = compareVersions(version, base);
|
|
2684
|
+
const [bMajor, bMinor] = base.split(".").map(Number);
|
|
2685
|
+
const [vMajor, vMinor] = version.split(".").map(Number);
|
|
2686
|
+
if (kind === "^") return cmp >= 0 && (bMajor === 0 ? vMajor === 0 && vMinor === bMinor : vMajor === bMajor);
|
|
2687
|
+
if (kind === "~") return cmp >= 0 && vMajor === bMajor && vMinor === bMinor;
|
|
2688
|
+
return { "=": cmp === 0, ">=": cmp >= 0, "<=": cmp <= 0, ">": cmp > 0, "<": cmp < 0 }[kind] ?? null;
|
|
2689
|
+
});
|
|
2690
|
+
return results.includes(null) ? null : results.every(Boolean);
|
|
2691
|
+
}
|
|
2692
|
+
function pendingMigrations(project2, lock) {
|
|
2693
|
+
const entries = Object.entries(lock.files).flatMap(([file, entry]) => entry.kind === "vendored" ? [{ file, ...entry }] : []);
|
|
2694
|
+
const planned = [];
|
|
2695
|
+
for (const { contract, migrations } of project2.system.components) {
|
|
2696
|
+
const entry = entries.find((e) => e.file === vendoredPath(project2, contract.source.file) && e.elements.includes(contract.id)) ?? entries.filter((e) => e.elements.includes(contract.id)).sort((a, b) => a.elements.length - b.elements.length)[0];
|
|
2697
|
+
if (!entry) continue;
|
|
2698
|
+
let at = entry.version;
|
|
2699
|
+
for (const spec of [...migrations].filter((m) => compareVersions(m.to, entry.version) > 0 && compareVersions(m.to, contract.version) <= 0).sort((a, b) => compareVersions(a.to, b.to) || a.id.localeCompare(b.id))) {
|
|
2700
|
+
planned.push({ spec, at, mismatch: admits(spec.from, at) === false });
|
|
2701
|
+
at = spec.to;
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
return planned.sort((a, b) => compareVersions(a.spec.to, b.spec.to) || a.spec.id.localeCompare(b.spec.id));
|
|
2705
|
+
}
|
|
2706
|
+
var Snapshot = class {
|
|
2707
|
+
saved = /* @__PURE__ */ new Map();
|
|
2708
|
+
root;
|
|
2709
|
+
constructor(root) {
|
|
2710
|
+
this.root = root;
|
|
2711
|
+
}
|
|
2712
|
+
async keep(files) {
|
|
2713
|
+
for (const file of files) if (!this.saved.has(file)) this.saved.set(file, await readTextOrNull(join16(this.root, file)));
|
|
2714
|
+
}
|
|
2715
|
+
/** A file's content before a step wrote it, unless it was kept already. */
|
|
2716
|
+
remember(file, content) {
|
|
2717
|
+
if (!this.saved.has(file)) this.saved.set(file, content);
|
|
2718
|
+
}
|
|
2719
|
+
/** Put back each file that changed; those that could not be are returned, to name them. */
|
|
2720
|
+
async restore() {
|
|
2721
|
+
const stuck = [];
|
|
2722
|
+
for (const [file, content] of this.saved) {
|
|
2723
|
+
const path = join16(this.root, file);
|
|
2724
|
+
try {
|
|
2725
|
+
if (content !== null) {
|
|
2726
|
+
if (await readTextOrNull(path) !== content) await writeFileAtomic(path, content);
|
|
2727
|
+
} else if (await lstat2(path).then((s) => s.isFile(), () => false)) await rm5(path);
|
|
2728
|
+
} catch {
|
|
2729
|
+
stuck.push(file);
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
return stuck;
|
|
2733
|
+
}
|
|
2734
|
+
};
|
|
2735
|
+
var gateFailures = (result) => result.gates.filter((g) => !g.ok).map((g) => `${g.name}: ${g.detail}`).join("; ");
|
|
2736
|
+
async function withRef(configFile, ref) {
|
|
2737
|
+
const text = await readTextOrNull(configFile) ?? "{}";
|
|
2738
|
+
const config = JSON.parse(text);
|
|
2739
|
+
return `${JSON.stringify({ ...config, source: { ...config.source, ref } }, null, 2)}
|
|
2740
|
+
`;
|
|
2741
|
+
}
|
|
2742
|
+
async function upgradeProject(project2, options = {}) {
|
|
2743
|
+
const lock = await readLock(project2.root);
|
|
2744
|
+
const source = project2.config.source;
|
|
2745
|
+
const system = { id: project2.system.config.id, name: project2.system.config.name };
|
|
2746
|
+
const to = { version: project2.system.config.version, commit: project2.designCommit ?? null, ref: options.to ?? ("git" in source ? source.ref : null) };
|
|
2747
|
+
const from = { version: lock?.systemVersion ?? null, commit: lock?.sourceCommit ?? null };
|
|
2748
|
+
const result = (status, parts, next2) => ({ status, system, from, to, sync: parts.sync ?? [], migrations: parts.migrations ?? [], blocked: parts.blocked ?? [], next: next2 });
|
|
2749
|
+
if (!lock) return result("blocked", { blocked: ["this product has never been synced with its System, so there is no earlier version to upgrade from"] }, "youiyoux sync");
|
|
2750
|
+
if (lock.system !== system.id) return result("blocked", { blocked: [`youi.lock.json is for System ${lock.system}, and the config names ${system.id}: an upgrade moves within one System`] }, "youiyoux sync, to switch Systems");
|
|
2751
|
+
const dry = await syncProject(project2, { dryRun: true });
|
|
2752
|
+
const conflicts = dry.actions.filter((a) => a.action === "conflict");
|
|
2753
|
+
const sync = dry.actions.filter((a) => WRITES.has(a.action) || a.action === "conflict" || a.action === "kept-local");
|
|
2754
|
+
const planned = pendingMigrations(project2, lock);
|
|
2755
|
+
const blocked = [
|
|
2756
|
+
...conflicts.map((a) => `${a.file}: ${a.detail ?? "conflicts with upstream"}`),
|
|
2757
|
+
...planned.filter((p) => p.mismatch).map((p) => `${p.spec.id} migrates from ${p.spec.from}, but ${p.spec.element} would be at ${p.at} here: no migration takes it from ${p.at} to ${p.spec.from}`)
|
|
2758
|
+
];
|
|
2759
|
+
if (blocked.length > 0) return result("blocked", { sync, blocked }, conflicts.length > 0 ? "youiyoux sync: resolve the conflicts it reports, then youiyoux sync --adopt records them, then youiyoux upgrade" : "ask the System's owners for the missing migration, or migrate by hand, then youiyoux sync");
|
|
2760
|
+
let staged = Object.fromEntries(dry.actions.filter((a) => a.role === "component" && dry.contents.has(a.file)).map((a) => [a.file, dry.contents.get(a.file)]));
|
|
2761
|
+
const previews = [];
|
|
2762
|
+
for (const { spec } of planned) {
|
|
2763
|
+
const preview = await runMigration({ ...project2, staged }, spec);
|
|
2764
|
+
previews.push(preview);
|
|
2765
|
+
if (preview.status === "rejected") return result("blocked", { sync, migrations: previews, blocked: [`${spec.id} would not hold: ${gateFailures(preview)}`] }, "fix what the failing gate names, or ask the System's owners; nothing was written");
|
|
2766
|
+
staged = { ...staged, ...Object.fromEntries(preview.changes.map((c) => [c.file, c.after])) };
|
|
2767
|
+
}
|
|
2768
|
+
const ref = options.to !== void 0 && "git" in source && options.to !== source.ref ? options.to : null;
|
|
2769
|
+
const changes = sync.some((a) => WRITES.has(a.action)) || previews.some((m) => m.status !== "noop") || ref !== null || lock.systemVersion !== to.version;
|
|
2770
|
+
if (!changes) return result("current", { sync, migrations: previews }, "nothing to do");
|
|
2771
|
+
if (!options.write) return result("preview", { sync, migrations: previews }, `youiyoux upgrade${options.to !== void 0 ? ` --to ${options.to}` : ""} --write`);
|
|
2772
|
+
const configFile = project2.configFile ?? join16(project2.root, PROJECT_FILE);
|
|
2773
|
+
const snapshot = new Snapshot(project2.root);
|
|
2774
|
+
const configBefore = await readTextOrNull(configFile);
|
|
2775
|
+
await snapshot.keep([LOCK_FILE2, ...dry.contents.keys(), ...dry.actions.filter((a) => a.action === "removed").map((a) => a.file), ...previews.flatMap((m) => m.changes.map((c) => c.file))]);
|
|
2776
|
+
const fail = async (why, done) => {
|
|
2777
|
+
const stuck = await snapshot.restore();
|
|
2778
|
+
if (ref !== null && configBefore !== null) await writeFileAtomic(configFile, configBefore).catch(() => stuck.push(PROJECT_FILE));
|
|
2779
|
+
const back = stuck.length === 0 ? "every file the upgrade wrote was put back" : `the files it wrote were put back except ${stuck.join(", ")}: restore those from git`;
|
|
2780
|
+
return result("blocked", { sync, migrations: previews, ...done, blocked: [`${why}; ${back}`] }, "run youiyoux upgrade again to see what changed");
|
|
2781
|
+
};
|
|
2782
|
+
try {
|
|
2783
|
+
if (ref !== null) await writeFileAtomic(configFile, await withRef(configFile, ref));
|
|
2784
|
+
const synced = await syncProject(project2);
|
|
2785
|
+
const late = synced.actions.filter((a) => a.action === "conflict");
|
|
2786
|
+
if (late.length > 0) return await fail(`the sync conflicted in ${late.map((a) => a.file).join(", ")}`, {});
|
|
2787
|
+
const applied = [];
|
|
2788
|
+
for (const { spec } of planned) {
|
|
2789
|
+
const run7 = await runMigration(project2, spec, { write: true });
|
|
2790
|
+
applied.push(run7);
|
|
2791
|
+
for (const change of run7.changes) snapshot.remember(change.file, change.before);
|
|
2792
|
+
if (run7.status === "rejected") return await fail(`${spec.id} did not hold on the written files: ${gateFailures(run7)}`, { migrations: applied });
|
|
2793
|
+
}
|
|
2794
|
+
const residuals = applied.reduce((n, m) => n + m.residuals.length, 0);
|
|
2795
|
+
return result("upgraded", { sync: synced.actions.filter((a) => WRITES.has(a.action) || a.action === "kept-local"), migrations: applied }, residuals > 0 ? `fix the ${residuals === 1 ? "site" : `${residuals} sites`} listed for a person, then youiyoux check` : "youiyoux check");
|
|
2796
|
+
} catch (error) {
|
|
2797
|
+
return fail(error instanceof Error ? error.message : String(error), {});
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
var ACTION = { created: style.ok, updated: style.live, merged: style.live, adopted: style.ok, removed: style.live, "kept-local": style.warn, conflict: style.error };
|
|
2801
|
+
function renderUpgrade(r, showDiff) {
|
|
2802
|
+
const version = (v) => v === null ? "never synced" : `v${v}`;
|
|
2803
|
+
const move = r.from.version === r.to.version ? `${version(r.to.version)}${r.from.commit && r.to.commit && r.from.commit !== r.to.commit ? style.dim(` (${r.from.commit.slice(0, 7)} \u2192 ${r.to.commit.slice(0, 7)})`) : ""}` : `${version(r.from.version)} \u2192 v${r.to.version}`;
|
|
2804
|
+
const verdict = { current: style.ok("up to date"), preview: style.live("preview: nothing written"), upgraded: style.ok("upgraded"), blocked: style.error("blocked: nothing written") }[r.status];
|
|
2805
|
+
const lines = [`${style.accent("upgrade")} ${r.system.name} ${move}${r.to.ref ? style.dim(` \xB7 ref ${r.to.ref}`) : ""} ${verdict}`, ""];
|
|
2806
|
+
const row = (a) => ` ${padEnd((ACTION[a.action] ?? style.dim)(a.action), 11)} ${a.file}${a.detail ? style.dim(` ${a.detail}`) : ""}`;
|
|
2807
|
+
const generated = r.sync.filter((a) => a.role !== "component" && a.action !== "conflict");
|
|
2808
|
+
lines.push(style.bold("sync"), ...r.sync.length === 0 ? [style.dim(" nothing to bring")] : r.sync.filter((a) => !generated.includes(a)).map(row));
|
|
2809
|
+
if (generated.length === 1) lines.push(row(generated[0]));
|
|
2810
|
+
else if (generated.length > 1) lines.push(` ${padEnd(style.live("updated"), 11)} ${plural(generated.length, "generated file")}${style.dim(` ${generated.slice(0, 3).map((a) => a.file).join(", ")}${generated.length > 3 ? ", \u2026" : ""}`)}`);
|
|
2811
|
+
lines.push("", style.bold("migrations"));
|
|
2812
|
+
if (r.migrations.length === 0) lines.push(style.dim(r.status === "blocked" && r.sync.length > 0 ? " not run" : r.status === "current" ? " none pending" : " none: no component this product has changed its API in this release"));
|
|
2813
|
+
for (const m of r.migrations) {
|
|
2814
|
+
const mark = m.status === "rejected" ? style.error("\u2716") : m.status === "noop" ? style.dim("\xB7") : style.ok("\u2713");
|
|
2815
|
+
const what = m.status === "noop" ? style.dim("nothing here uses what it changes") : `${plural(m.edited, "site")} rewritten in ${plural(m.changes.length, "file")}${m.residuals.length > 0 ? ` \xB7 ${style.warn(`${plural(m.residuals.length, "site")} for a person`)}` : ""}`;
|
|
2816
|
+
lines.push(` ${mark} ${m.migration} ${what}`);
|
|
2817
|
+
for (const gate of m.gates.filter((g) => !g.ok)) lines.push(` ${style.error(gate.name)} ${style.dim(gate.detail)}`);
|
|
2818
|
+
for (const residual of m.residuals) lines.push(` ${style.dim(`${residual.file}:${residual.line}`)} ${residual.reason}`);
|
|
2819
|
+
}
|
|
2820
|
+
const files = /* @__PURE__ */ new Map();
|
|
2821
|
+
for (const change of r.migrations.flatMap((m) => m.changes)) files.set(change.file, { before: files.get(change.file)?.before ?? change.before, after: change.after });
|
|
2822
|
+
if (showDiff) for (const [file, { before, after }] of files) lines.push("", ...unifiedDiff(file, before, after).trimEnd().split("\n").map((l) => l.startsWith("+") && !l.startsWith("+++") ? style.ok(l) : l.startsWith("-") && !l.startsWith("---") ? style.error(l) : style.dim(l)));
|
|
2823
|
+
if (r.blocked.length > 0) lines.push("", ...r.blocked.map((b) => `${style.error("\u2716")} ${b}`));
|
|
2824
|
+
lines.push("", `${style.bold("Next:")} ${r.next}`);
|
|
2825
|
+
return lines.join("\n");
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2653
2828
|
// ../cli/src/status.ts
|
|
2654
2829
|
import { realpath as realpath5 } from "node:fs/promises";
|
|
2655
|
-
import { dirname as dirname9, join as
|
|
2830
|
+
import { dirname as dirname9, join as join17, relative as relative8, resolve as resolve10 } from "node:path";
|
|
2656
2831
|
var placeOf = (cwd, root) => {
|
|
2657
2832
|
const rel = relative8(cwd, root) || ".";
|
|
2658
2833
|
return rel.split(/[\\/]/).filter((part) => part === "..").length > 1 ? resolve10(root) : rel;
|
|
2659
2834
|
};
|
|
2660
|
-
var
|
|
2835
|
+
var WRITES2 = /* @__PURE__ */ new Set(["created", "updated", "merged", "adopted", "conflict", "removed"]);
|
|
2661
2836
|
function sourceOf(project2) {
|
|
2662
2837
|
if (project2.linked) return `your checkout ${project2.linked}`;
|
|
2663
2838
|
const source = project2.config.source;
|
|
@@ -2665,9 +2840,10 @@ function sourceOf(project2) {
|
|
|
2665
2840
|
if ("git" in source) return `git ${source.git} at ${source.ref}`;
|
|
2666
2841
|
return resolve10(project2.root) === resolve10(project2.repo.root) ? "this repo" : `path ${source.path}`;
|
|
2667
2842
|
}
|
|
2668
|
-
function nextStep(s) {
|
|
2843
|
+
function nextStep(s, migrations) {
|
|
2669
2844
|
if (s.sync.state === "never") return "youiyoux sync: this product has never been synced with its System";
|
|
2670
2845
|
if (s.sync.state === "conflict") return "youiyoux sync: resolve the conflicts it reports, then youiyoux sync --adopt records them";
|
|
2846
|
+
if (migrations > 0) return `youiyoux upgrade: ${s.system.name} v${s.system.version} comes with ${plural(migrations, "migration")} for this product's code, which upgrade runs with the sync`;
|
|
2671
2847
|
if (s.sync.state === "behind") return `youiyoux sync: ${plural(s.sync.changes.length, "file")} would change`;
|
|
2672
2848
|
if (s.check.incomplete) return "youiyoux check: some files or rules could not be checked, and it says which";
|
|
2673
2849
|
if (s.check.errors > 0) return `youiyoux check: fix ${plural(s.check.errors, "error")}`;
|
|
@@ -2678,13 +2854,13 @@ function nextStep(s) {
|
|
|
2678
2854
|
async function projectStatus(project2, cwd = process.cwd()) {
|
|
2679
2855
|
const lock = await readLock(project2.root);
|
|
2680
2856
|
const { actions } = await syncProject(project2, { dryRun: true });
|
|
2681
|
-
const changes = actions.filter((a) =>
|
|
2857
|
+
const changes = actions.filter((a) => WRITES2.has(a.action)).map((a) => ({ file: a.file, action: a.action }));
|
|
2682
2858
|
const baselineFile2 = baselinePath(project2);
|
|
2683
2859
|
const check = await runCheck(project2, { baseline: await readTextOrNull(baselineFile2) === null ? null : baselineFile2 });
|
|
2684
2860
|
const comparison = check.baseline?.comparison;
|
|
2685
2861
|
const counted = comparison ? [...comparison.new, ...comparison.regressed] : check.violations;
|
|
2686
2862
|
const usages = check.scan.report.usages;
|
|
2687
|
-
const { RequestStore } = await import("./src-
|
|
2863
|
+
const { RequestStore } = await import("./src-6SNQVIZS.js");
|
|
2688
2864
|
const requests = await new RequestStore(project2.root, project2.config.id).list();
|
|
2689
2865
|
const status = {
|
|
2690
2866
|
id: project2.config.id,
|
|
@@ -2702,7 +2878,7 @@ async function projectStatus(project2, cwd = process.cwd()) {
|
|
|
2702
2878
|
components: { system: project2.system.components.length, used: new Set(usages.map((u) => u.element)).size, sites: usages.length },
|
|
2703
2879
|
requests: { open: requests.requests.filter((r) => r.status === "open").length, addressed: requests.requests.filter((r) => r.status === "addressed").length, unreadable: requests.unreadable.length }
|
|
2704
2880
|
};
|
|
2705
|
-
return { ...status, next: nextStep(status) };
|
|
2881
|
+
return { ...status, next: nextStep(status, lock ? pendingMigrations(project2, lock).length : 0) };
|
|
2706
2882
|
}
|
|
2707
2883
|
async function statusTargets(cwd, named2) {
|
|
2708
2884
|
if (named2) return { roots: [resolve10(named2)], workspace: null };
|
|
@@ -2710,7 +2886,7 @@ async function statusTargets(cwd, named2) {
|
|
|
2710
2886
|
if (product2) return { roots: [product2], workspace: null };
|
|
2711
2887
|
const at = findUp(cwd, WORKSPACE_FILE);
|
|
2712
2888
|
if (at) {
|
|
2713
|
-
const file =
|
|
2889
|
+
const file = join17(at, WORKSPACE_FILE);
|
|
2714
2890
|
const workspace = await readDefinition(file, WorkspaceConfig);
|
|
2715
2891
|
return { roots: workspace.projects.map((p) => resolve10(at, p)), workspace: file };
|
|
2716
2892
|
}
|
|
@@ -2732,7 +2908,7 @@ async function workspaceStatus(cwd, named2) {
|
|
|
2732
2908
|
projects.push(await projectStatus(await loadProject(root), cwd));
|
|
2733
2909
|
} catch (error) {
|
|
2734
2910
|
const label = placeOf(cwd, root);
|
|
2735
|
-
projects.push({ root: label, error: error instanceof Error ? error.message : String(error), next: await readTextOrNull(
|
|
2911
|
+
projects.push({ root: label, error: error instanceof Error ? error.message : String(error), next: await readTextOrNull(join17(root, PROJECT_FILE)) === null ? `youiyoux adopt or youiyoux init --design <dir> in ${label}` : `fix ${join17(label, PROJECT_FILE)}` });
|
|
2736
2912
|
}
|
|
2737
2913
|
}
|
|
2738
2914
|
return { schema: "youi.status/v1", generatedAt: (/* @__PURE__ */ new Date()).toISOString(), workspace: workspace ? relative8(cwd, workspace) || WORKSPACE_FILE : null, projects };
|
|
@@ -2829,14 +3005,14 @@ async function startWorkspaceHub(options) {
|
|
|
2829
3005
|
}
|
|
2830
3006
|
|
|
2831
3007
|
// ../cli/src/index-store.ts
|
|
2832
|
-
import { appendFile, mkdir as mkdir4, readFile as readFile6, stat as stat2, rename as rename2, mkdtemp as mkdtemp4, rm as
|
|
2833
|
-
import { dirname as dirname10, join as
|
|
3008
|
+
import { appendFile, mkdir as mkdir4, readFile as readFile6, stat as stat2, rename as rename2, mkdtemp as mkdtemp4, rm as rm6 } from "node:fs/promises";
|
|
3009
|
+
import { dirname as dirname10, join as join18, resolve as resolve11 } from "node:path";
|
|
2834
3010
|
var SOURCES_FILE = "index-sources.json";
|
|
2835
3011
|
var SCANS_LOG = "scans.jsonl";
|
|
2836
3012
|
var EMPTY = { discover: null, inventories: [], projects: [] };
|
|
2837
3013
|
async function readIndexSources(home) {
|
|
2838
3014
|
try {
|
|
2839
|
-
const raw = JSON.parse(await readFile6(
|
|
3015
|
+
const raw = JSON.parse(await readFile6(join18(home, SOURCES_FILE), "utf8"));
|
|
2840
3016
|
return { discover: raw.discover ?? null, inventories: raw.inventories ?? [], projects: raw.projects ?? [] };
|
|
2841
3017
|
} catch {
|
|
2842
3018
|
return EMPTY;
|
|
@@ -2849,14 +3025,14 @@ async function noteSource(home, change) {
|
|
|
2849
3025
|
inventories: change.inventory && !sources.inventories.includes(change.inventory) ? [...sources.inventories, change.inventory] : sources.inventories,
|
|
2850
3026
|
projects: change.project ? [...sources.projects.filter((p) => p.root !== change.project.root), change.project] : sources.projects
|
|
2851
3027
|
};
|
|
2852
|
-
await writeFileAtomic(
|
|
3028
|
+
await writeFileAtomic(join18(home, SOURCES_FILE), `${JSON.stringify(next2, null, 2)}
|
|
2853
3029
|
`);
|
|
2854
3030
|
}
|
|
2855
3031
|
async function recordInventory(store, home, report, file) {
|
|
2856
3032
|
const run7 = inventoryRun(report, resolve11(file));
|
|
2857
3033
|
const logged = { run: run7.run, source: run7.source, scannedAt: run7.scannedAt, projects: run7.projects, families: run7.families };
|
|
2858
3034
|
await mkdir4(home, { recursive: true });
|
|
2859
|
-
await appendFile(
|
|
3035
|
+
await appendFile(join18(home, SCANS_LOG), `${JSON.stringify({ schema: "youi.scan-log/v1", ...logged })}
|
|
2860
3036
|
`);
|
|
2861
3037
|
await store.recordInventory(run7);
|
|
2862
3038
|
await noteSource(home, { inventory: run7.source });
|
|
@@ -2867,7 +3043,7 @@ async function recordProject(store, project2, usage) {
|
|
|
2867
3043
|
await store.replaceGraph(`project:${project2.root}`, projectGraph({ project: project2.config.id, rules: project2.system.rules, components: project2.system.components.map((c) => ({ id: c.contract.id, name: c.contract.name })), usage }));
|
|
2868
3044
|
}
|
|
2869
3045
|
async function readLog(home) {
|
|
2870
|
-
const text = await readFile6(
|
|
3046
|
+
const text = await readFile6(join18(home, SCANS_LOG), "utf8").catch(() => "");
|
|
2871
3047
|
return text.split("\n").flatMap((line) => {
|
|
2872
3048
|
if (!line.trim()) return [];
|
|
2873
3049
|
try {
|
|
@@ -2884,7 +3060,7 @@ async function rebuildIndex(path, options = {}) {
|
|
|
2884
3060
|
const home = indexHome(path, env);
|
|
2885
3061
|
await mkdir4(dirname10(path), { recursive: true });
|
|
2886
3062
|
const scratch = !env.DATABASE_URL ? await mkdtemp4(`${path}.rebuild-`) : null;
|
|
2887
|
-
const target = scratch ?
|
|
3063
|
+
const target = scratch ? join18(scratch, "index.db") : path;
|
|
2888
3064
|
const store = scratch ? await openSqlite(target) : await sharedStore(path, env);
|
|
2889
3065
|
try {
|
|
2890
3066
|
if (env.DATABASE_URL) await store.reset();
|
|
@@ -2892,7 +3068,7 @@ async function rebuildIndex(path, options = {}) {
|
|
|
2892
3068
|
const sources = await readIndexSources(home);
|
|
2893
3069
|
const cache = options.discoverCache ?? sources.discover;
|
|
2894
3070
|
let discover = { cache, chosen: 0, all: 0 };
|
|
2895
|
-
if (cache && await stat2(
|
|
3071
|
+
if (cache && await stat2(join18(cache, "index.json")).then(() => true, () => false)) {
|
|
2896
3072
|
const loaded = await ingestCatalog(store, cache);
|
|
2897
3073
|
discover = { cache, chosen: loaded.chosen, all: loaded.all };
|
|
2898
3074
|
}
|
|
@@ -2920,7 +3096,7 @@ async function rebuildIndex(path, options = {}) {
|
|
|
2920
3096
|
}
|
|
2921
3097
|
try {
|
|
2922
3098
|
const project2 = await loadProject(source.root, source.options);
|
|
2923
|
-
const usage = ScanReport.safeParse(await readJson(source.usage ??
|
|
3099
|
+
const usage = ScanReport.safeParse(await readJson(source.usage ?? join18(project2.root, ".youi/usage.json")));
|
|
2924
3100
|
await recordProject(store, project2, usage.success ? usage.data : null);
|
|
2925
3101
|
projects++;
|
|
2926
3102
|
} catch (error) {
|
|
@@ -2955,7 +3131,7 @@ async function rebuildIndex(path, options = {}) {
|
|
|
2955
3131
|
} finally {
|
|
2956
3132
|
if (scratch) {
|
|
2957
3133
|
await store.close();
|
|
2958
|
-
await
|
|
3134
|
+
await rm6(scratch, { recursive: true, force: true });
|
|
2959
3135
|
}
|
|
2960
3136
|
}
|
|
2961
3137
|
}
|
|
@@ -3139,7 +3315,7 @@ function renderAdoptionRequest(request) {
|
|
|
3139
3315
|
// ../cli/src/report/run.ts
|
|
3140
3316
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
3141
3317
|
import { mkdir as mkdir5, rename as rename3, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
|
|
3142
|
-
import { join as
|
|
3318
|
+
import { join as join25, relative as relative10, resolve as resolve14 } from "node:path";
|
|
3143
3319
|
|
|
3144
3320
|
// ../cli/src/report/card.ts
|
|
3145
3321
|
import { deflateSync } from "node:zlib";
|
|
@@ -3375,7 +3551,7 @@ function drawCard(input) {
|
|
|
3375
3551
|
|
|
3376
3552
|
// ../cli/src/report/model.ts
|
|
3377
3553
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
3378
|
-
import { join as
|
|
3554
|
+
import { join as join22 } from "node:path";
|
|
3379
3555
|
|
|
3380
3556
|
// ../cli/src/report/filters.ts
|
|
3381
3557
|
var SHOWCASE_GLOBS = ["**/{__stories__,.storybook,storybook,storybook-static,example,examples,demo,demos,playground,showcase,showcases}/**", "**/*.stories.*", "**/*.story.*"];
|
|
@@ -3502,11 +3678,11 @@ function publicLook(caption) {
|
|
|
3502
3678
|
|
|
3503
3679
|
// ../cli/src/report/groups.ts
|
|
3504
3680
|
import { existsSync as existsSync3 } from "node:fs";
|
|
3505
|
-
import { join as
|
|
3681
|
+
import { join as join20 } from "node:path";
|
|
3506
3682
|
|
|
3507
3683
|
// ../cli/src/report/imports.ts
|
|
3508
3684
|
import { realpathSync } from "node:fs";
|
|
3509
|
-
import { dirname as dirname11, join as
|
|
3685
|
+
import { dirname as dirname11, join as join19, relative as relative9, resolve as resolve12 } from "node:path";
|
|
3510
3686
|
import ts from "typescript";
|
|
3511
3687
|
var resolvers = /* @__PURE__ */ new Map();
|
|
3512
3688
|
function resolverOf(root) {
|
|
@@ -3525,13 +3701,13 @@ function clearImportCache() {
|
|
|
3525
3701
|
}
|
|
3526
3702
|
async function verifiedImport(root, keeper, from, suggested) {
|
|
3527
3703
|
const { options, cache } = resolverOf(root);
|
|
3528
|
-
let local = relative9(dirname11(
|
|
3704
|
+
let local = relative9(dirname11(join19(root, from)), join19(root, keeper)).replaceAll("\\", "/").replace(/\.(tsx?|jsx?|mjs)$/, "");
|
|
3529
3705
|
if (!local.startsWith(".")) local = `./${local}`;
|
|
3530
3706
|
for (const specifier of /* @__PURE__ */ new Set([suggested, local])) {
|
|
3531
3707
|
const found = ts.resolveModuleName(specifier, resolve12(root, from), options, ts.sys, cache).resolvedModule?.resolvedFileName;
|
|
3532
3708
|
if (found) {
|
|
3533
3709
|
try {
|
|
3534
|
-
if (realpathSync(found) === realpathSync(
|
|
3710
|
+
if (realpathSync(found) === realpathSync(join19(root, keeper))) return specifier;
|
|
3535
3711
|
} catch {
|
|
3536
3712
|
}
|
|
3537
3713
|
}
|
|
@@ -3939,7 +4115,7 @@ function factsOf(project2, id, modules, eligible, workspaceNames, dependencies,
|
|
|
3939
4115
|
if (dirs.has(file.slice(0, at))) break;
|
|
3940
4116
|
dirs.add(file.slice(0, at));
|
|
3941
4117
|
}
|
|
3942
|
-
const roots = [...dirs].filter((dir) => existsSync3(
|
|
4118
|
+
const roots = [...dirs].filter((dir) => existsSync3(join20(project2.root, dir, "package.json"))).sort((a, b) => b.length - a.length);
|
|
3943
4119
|
const nested = (file) => roots.find((dir) => file.startsWith(`${dir}/`)) ?? "";
|
|
3944
4120
|
return { project: project2, id, dependencies, packageImports, jsxCounts, eligible, twins, dirs, importer, packageOf: nested };
|
|
3945
4121
|
}
|
|
@@ -3947,11 +4123,11 @@ function factsOf(project2, id, modules, eligible, workspaceNames, dependencies,
|
|
|
3947
4123
|
// ../cli/src/report/projects.ts
|
|
3948
4124
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
3949
4125
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
3950
|
-
import { basename as basename4, join as
|
|
4126
|
+
import { basename as basename4, join as join21, resolve as resolve13 } from "node:path";
|
|
3951
4127
|
var UI_FILES = ["**/*.{tsx,jsx,astro,vue,svelte}"];
|
|
3952
4128
|
var strings = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
3953
4129
|
async function workspaceGlobs(root, pkg) {
|
|
3954
|
-
const pnpm = await readFile7(
|
|
4130
|
+
const pnpm = await readFile7(join21(root, "pnpm-workspace.yaml"), "utf8").catch(() => null);
|
|
3955
4131
|
if (pnpm !== null) {
|
|
3956
4132
|
try {
|
|
3957
4133
|
const globs2 = strings((0, import_yaml3.parse)(pnpm)?.packages);
|
|
@@ -3966,7 +4142,7 @@ async function workspaceGlobs(root, pkg) {
|
|
|
3966
4142
|
var hasUi = async (dir) => (await findFiles(dir, UI_FILES, DEFAULT_EXCLUDE)).length > 0;
|
|
3967
4143
|
async function findProjects(dir) {
|
|
3968
4144
|
const root = resolve13(dir);
|
|
3969
|
-
const pkg = await readJson(
|
|
4145
|
+
const pkg = await readJson(join21(root, "package.json"));
|
|
3970
4146
|
const name = typeof pkg?.name === "string" && pkg.name.trim() ? pkg.name.trim() : basename4(root);
|
|
3971
4147
|
const single = { dir: ".", root, name: typeof pkg?.name === "string" ? pkg.name : null };
|
|
3972
4148
|
const workspace = await workspaceGlobs(root, pkg);
|
|
@@ -3977,12 +4153,12 @@ async function findProjects(dir) {
|
|
|
3977
4153
|
const projects = [];
|
|
3978
4154
|
const skipped = [];
|
|
3979
4155
|
for (const member of members) {
|
|
3980
|
-
const memberRoot =
|
|
4156
|
+
const memberRoot = join21(root, member);
|
|
3981
4157
|
if (!await hasUi(memberRoot)) {
|
|
3982
4158
|
skipped.push(member);
|
|
3983
4159
|
continue;
|
|
3984
4160
|
}
|
|
3985
|
-
const memberPkg = await readJson(
|
|
4161
|
+
const memberPkg = await readJson(join21(memberRoot, "package.json"));
|
|
3986
4162
|
projects.push({ dir: member, root: memberRoot, name: typeof memberPkg?.name === "string" ? memberPkg.name : null });
|
|
3987
4163
|
}
|
|
3988
4164
|
if (projects.length === 0) return { root, name, layout: `one project (${workspace.source} names no package with UI files)`, projects: [single], skipped };
|
|
@@ -4009,7 +4185,7 @@ var Lines = class {
|
|
|
4009
4185
|
if (!this.enabled) return { at };
|
|
4010
4186
|
let lines = this.files.get(file);
|
|
4011
4187
|
if (!lines) {
|
|
4012
|
-
lines = (await readFile8(
|
|
4188
|
+
lines = (await readFile8(join22(this.root, file), "utf8").catch(() => "")).split("\n");
|
|
4013
4189
|
this.files.set(file, lines);
|
|
4014
4190
|
}
|
|
4015
4191
|
const code = lines[line - 1]?.trim();
|
|
@@ -4029,7 +4205,7 @@ async function modulesOf(project2, target, failed2) {
|
|
|
4029
4205
|
for (const file of target.files) {
|
|
4030
4206
|
if (isShowcase(file)) continue;
|
|
4031
4207
|
try {
|
|
4032
|
-
const module = await parseModule(file, await readFile8(
|
|
4208
|
+
const module = await parseModule(file, await readFile8(join22(project2.root, file), "utf8"));
|
|
4033
4209
|
if (module) modules.push(module);
|
|
4034
4210
|
} catch (error) {
|
|
4035
4211
|
failed2.push(`${repoPath(project2.dir, file)}: ${errorText(error)}`);
|
|
@@ -4133,7 +4309,7 @@ async function analyseProject(project2, index, inventory, inventoryError, worksp
|
|
|
4133
4309
|
incomplete.push(`Library choices were not compared (${errorText(error)}); run ${NPX} detect ${project2.dir} to see why`);
|
|
4134
4310
|
}
|
|
4135
4311
|
}
|
|
4136
|
-
const pkg = await readFile8(
|
|
4312
|
+
const pkg = await readFile8(join22(project2.root, "package.json"), "utf8").then((text) => JSON.parse(text), () => null);
|
|
4137
4313
|
const dependencies = new Set(["dependencies", "devDependencies", "peerDependencies"].flatMap((key2) => Object.keys(pkg?.[key2] ?? {})));
|
|
4138
4314
|
const importer = changeProject ? await importOf(changeProject) : () => "";
|
|
4139
4315
|
const facts = factsOf(project2, projectId ?? null, modules, eligible, workspaceNames, dependencies, target?.files ?? [], importer);
|
|
@@ -4577,7 +4753,7 @@ ${model.projects.map((p) => projectSection(p, many, looks)).join("\n")}
|
|
|
4577
4753
|
import { spawn as spawn2 } from "node:child_process";
|
|
4578
4754
|
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "node:fs";
|
|
4579
4755
|
import { homedir as homedir2 } from "node:os";
|
|
4580
|
-
import { dirname as dirname12, join as
|
|
4756
|
+
import { dirname as dirname12, join as join23 } from "node:path";
|
|
4581
4757
|
var LOOKS_PER_PROJECT = 4;
|
|
4582
4758
|
var DOWNLOAD_SIZE = "~100 MB";
|
|
4583
4759
|
var DEPENDENCIES = "Install the repo's dependencies to see rendered looks";
|
|
@@ -4585,26 +4761,26 @@ var UNDRAWABLE = /not installed|loads no stylesheet|drawn from (?:its|their) (?:
|
|
|
4585
4761
|
var playwrightDir = () => dirname12(playwrightCli());
|
|
4586
4762
|
function browsersPath(env) {
|
|
4587
4763
|
const set = env.PLAYWRIGHT_BROWSERS_PATH;
|
|
4588
|
-
if (set === "0") return
|
|
4764
|
+
if (set === "0") return join23(playwrightDir(), ".local-browsers");
|
|
4589
4765
|
if (set) return set;
|
|
4590
|
-
if (process.platform === "darwin") return
|
|
4591
|
-
if (process.platform === "win32") return
|
|
4592
|
-
return
|
|
4766
|
+
if (process.platform === "darwin") return join23(homedir2(), "Library/Caches/ms-playwright");
|
|
4767
|
+
if (process.platform === "win32") return join23(env.LOCALAPPDATA ?? join23(homedir2(), "AppData/Local"), "ms-playwright");
|
|
4768
|
+
return join23(env.XDG_CACHE_HOME ?? join23(homedir2(), ".cache"), "ms-playwright");
|
|
4593
4769
|
}
|
|
4594
4770
|
function chromiumStatus(env = process.env) {
|
|
4595
4771
|
if (env.YOUI_CHROMIUM) return { available: existsSync4(env.YOUI_CHROMIUM), where: env.YOUI_CHROMIUM };
|
|
4596
4772
|
try {
|
|
4597
|
-
const browsers = JSON.parse(readFileSync2(
|
|
4773
|
+
const browsers = JSON.parse(readFileSync2(join23(playwrightDir(), "browsers.json"), "utf8"));
|
|
4598
4774
|
const revision2 = browsers.browsers.find((b) => b.name === "chromium-headless-shell")?.revision;
|
|
4599
|
-
const dir =
|
|
4600
|
-
return { available: revision2 !== void 0 && existsSync4(
|
|
4775
|
+
const dir = join23(browsersPath(env), `chromium_headless_shell-${revision2}`);
|
|
4776
|
+
return { available: revision2 !== void 0 && existsSync4(join23(dir, "INSTALLATION_COMPLETE")), where: dir };
|
|
4601
4777
|
} catch {
|
|
4602
4778
|
return { available: false, where: "playwright-core is not installed" };
|
|
4603
4779
|
}
|
|
4604
4780
|
}
|
|
4605
4781
|
function downloadChromium() {
|
|
4606
4782
|
return new Promise((resolve16) => {
|
|
4607
|
-
const child = spawn2(process.execPath, [
|
|
4783
|
+
const child = spawn2(process.execPath, [join23(playwrightDir(), "cli.js"), "install", "chromium-headless-shell"], { stdio: ["ignore", 2, 2] });
|
|
4608
4784
|
child.on("error", () => resolve16(false));
|
|
4609
4785
|
child.on("close", (code) => resolve16(code === 0));
|
|
4610
4786
|
});
|
|
@@ -4620,9 +4796,9 @@ async function addLooks(model, repoRoot, options = {}) {
|
|
|
4620
4796
|
const where2 = section.dir === "." ? "this repo" : section.dir;
|
|
4621
4797
|
try {
|
|
4622
4798
|
const installed = (name) => {
|
|
4623
|
-
let dir =
|
|
4799
|
+
let dir = join23(repoRoot, section.dir);
|
|
4624
4800
|
while (true) {
|
|
4625
|
-
if (existsSync4(
|
|
4801
|
+
if (existsSync4(join23(dir, "node_modules", name, "package.json"))) return true;
|
|
4626
4802
|
if (dir === repoRoot || dirname12(dir) === dir) return false;
|
|
4627
4803
|
dir = dirname12(dir);
|
|
4628
4804
|
}
|
|
@@ -4631,13 +4807,13 @@ async function addLooks(model, repoRoot, options = {}) {
|
|
|
4631
4807
|
missing.push(where2);
|
|
4632
4808
|
continue;
|
|
4633
4809
|
}
|
|
4634
|
-
const projectRoot =
|
|
4810
|
+
const projectRoot = join23(repoRoot, section.dir);
|
|
4635
4811
|
const target = await loadInventoryTarget(projectRoot);
|
|
4636
4812
|
if (findStylesheets(projectRoot, target.files, { tsconfig: target.tsconfig, override: target.specimenCss, templates: target.templates }).found.length === 0) {
|
|
4637
4813
|
missing.push(where2);
|
|
4638
4814
|
continue;
|
|
4639
4815
|
}
|
|
4640
|
-
const report = await renderShots(
|
|
4816
|
+
const report = await renderShots(join23(repoRoot, section.dir), names, { download: false, base: "HEAD", ...options.executablePath ? { executablePath: options.executablePath } : {}, ...options.cache ? { cache: options.cache } : {}, ...options.log ? { log: options.log } : {} });
|
|
4641
4817
|
const unavailable = report.notes.some((note) => UNDRAWABLE.test(note));
|
|
4642
4818
|
if (unavailable) {
|
|
4643
4819
|
missing.push(where2);
|
|
@@ -4709,7 +4885,7 @@ function renderMarkdown(model, reportFile) {
|
|
|
4709
4885
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
4710
4886
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
4711
4887
|
import { homedir as homedir3, userInfo as userInfo2 } from "node:os";
|
|
4712
|
-
import { join as
|
|
4888
|
+
import { join as join24 } from "node:path";
|
|
4713
4889
|
var REDACTED = "[redacted]";
|
|
4714
4890
|
var OUTSIDE = "[path outside the repo]";
|
|
4715
4891
|
var MIN_VALUE = 6;
|
|
@@ -4721,7 +4897,7 @@ async function dotenvValues(root) {
|
|
|
4721
4897
|
const files = await findFiles(root, [".env", ".env.*", "**/.env", "**/.env.*"]).catch(() => []);
|
|
4722
4898
|
const values = [];
|
|
4723
4899
|
for (const file of files) {
|
|
4724
|
-
const text = await readFile9(
|
|
4900
|
+
const text = await readFile9(join24(root, file), "utf8").catch(() => "");
|
|
4725
4901
|
for (const line of text.split(/\r?\n/)) {
|
|
4726
4902
|
const match = /^\s*(?:export\s+)?[A-Za-z_][A-Za-z0-9_.-]*\s*=\s*(.*)$/.exec(line);
|
|
4727
4903
|
if (!match) continue;
|
|
@@ -4894,7 +5070,7 @@ async function runReport(options = {}, io = {}) {
|
|
|
4894
5070
|
const clean = redactor.model(model);
|
|
4895
5071
|
const outDir = resolve14(options.out ?? root);
|
|
4896
5072
|
await mkdir5(outDir, { recursive: true });
|
|
4897
|
-
const files = { report:
|
|
5073
|
+
const files = { report: join25(outDir, REPORT_FILE), card: join25(outDir, CARD_FILE), summary: join25(outDir, SUMMARY_FILE) };
|
|
4898
5074
|
const t = clean.totals;
|
|
4899
5075
|
const card = {
|
|
4900
5076
|
repo: redactor.scrub(clean.repo),
|
|
@@ -5044,6 +5220,12 @@ ${style.bold("System")} ${style.dim("approved elements: build only with these")
|
|
|
5044
5220
|
plan <component> --patch <json|file> classify a contract change and show its impact
|
|
5045
5221
|
plan --token <id> [--value v] impact of a token change
|
|
5046
5222
|
migrate <migration.yaml> [--write] [--diff] gated codemod for props and renamed or removed exports
|
|
5223
|
+
upgrade [--to ref] [--write] [--diff]
|
|
5224
|
+
move to the System's new release in one step: the sync, and each component's
|
|
5225
|
+
migrations past the version youi.lock.json records, run as gated dry runs on
|
|
5226
|
+
the components as the sync would bring them; a preview unless --write, which
|
|
5227
|
+
writes all of it or, if a step fails, puts every file back. --to moves a git
|
|
5228
|
+
source to another tag or branch (written to the config's source.ref)
|
|
5047
5229
|
(imports, re-exports, uses); a dry run that prints the diff and the sites
|
|
5048
5230
|
left for a person (file:line, why) unless --write; --diff shows it after --write too
|
|
5049
5231
|
rules [--preview <rule.yaml>] whether each rule is checked; preview a draft rule on the current scan
|
|
@@ -5159,6 +5341,7 @@ var OPTIONS = {
|
|
|
5159
5341
|
inventory: { type: "string" },
|
|
5160
5342
|
package: { type: "string" },
|
|
5161
5343
|
fork: { type: "boolean", default: false },
|
|
5344
|
+
to: { type: "string" },
|
|
5162
5345
|
cache: { type: "string" },
|
|
5163
5346
|
role: { type: "string" },
|
|
5164
5347
|
license: { type: "string" },
|
|
@@ -5196,7 +5379,7 @@ async function readJsonOrFile(value) {
|
|
|
5196
5379
|
async function cmdScan(values) {
|
|
5197
5380
|
const p = await project(values);
|
|
5198
5381
|
const { report } = await scanProject(p);
|
|
5199
|
-
const out = values.out ??
|
|
5382
|
+
const out = values.out ?? join26(p.root, ".youi/usage.json");
|
|
5200
5383
|
await writeFileAtomic(resolve15(out), `${JSON.stringify(report)}
|
|
5201
5384
|
`);
|
|
5202
5385
|
const recorded = await recordUsage(values, p, report, resolve15(out));
|
|
@@ -5243,7 +5426,7 @@ async function cmdInventory(values) {
|
|
|
5243
5426
|
if (values.history) return cmdHistory(values, []);
|
|
5244
5427
|
const dirs = inventoryDirs(values);
|
|
5245
5428
|
const report = await scanInventory(values, dirs);
|
|
5246
|
-
const out = resolve15(values.out ??
|
|
5429
|
+
const out = resolve15(values.out ?? join26(dirs[0], ".youi/inventory.json"));
|
|
5247
5430
|
await writeFileAtomic(out, `${JSON.stringify(report, null, 2)}
|
|
5248
5431
|
`);
|
|
5249
5432
|
const recorded = await recordScan(values, report, out);
|
|
@@ -5273,7 +5456,7 @@ async function cmdIndex(values, positionals) {
|
|
|
5273
5456
|
const [action, ...rest] = positionals;
|
|
5274
5457
|
const { path, home } = indexOf(values);
|
|
5275
5458
|
if (action === "path") {
|
|
5276
|
-
if (values.json) json3({ store: storeLocation({ path }), sources:
|
|
5459
|
+
if (values.json) json3({ store: storeLocation({ path }), sources: join26(home, SOURCES_FILE), scans: join26(home, SCANS_LOG) });
|
|
5277
5460
|
else print(storeLocation({ path }));
|
|
5278
5461
|
return 0;
|
|
5279
5462
|
}
|
|
@@ -5444,15 +5627,23 @@ async function cmdLibrary(values, positionals) {
|
|
|
5444
5627
|
async function cmdSync(values) {
|
|
5445
5628
|
const p = await loadProject(values.project ?? process.cwd(), { ...loadOptions(values), refreshDesign: true });
|
|
5446
5629
|
const result = await syncProject(p, { dryRun: values["dry-run"], adopt: values.adopt });
|
|
5447
|
-
if (values.json) json3(result);
|
|
5630
|
+
if (values.json) json3({ actions: result.actions, lock: result.lock, unknownTools: result.unknownTools });
|
|
5448
5631
|
else print([renderSync(result, values["dry-run"]), ...p.linked ? [style.warn(`! linked: the design system is your checkout ${p.linked}, not the config's source (youiyoux unlink to undo)`)] : []].join("\n"));
|
|
5449
5632
|
return result.actions.some((a) => a.action === "conflict") ? 1 : 0;
|
|
5450
5633
|
}
|
|
5634
|
+
async function cmdUpgrade(values) {
|
|
5635
|
+
if (values.to !== void 0 && !/^[\w][\w./-]*$/.test(values.to)) throw new UsageError(`--to ${JSON.stringify(values.to)}: expected a git tag, branch or commit`);
|
|
5636
|
+
const p = await loadProject(values.project ?? process.cwd(), { ...loadOptions(values), refreshDesign: true, ...values.to !== void 0 ? { ref: values.to } : {} });
|
|
5637
|
+
const result = await upgradeProject(p, { write: values.write, ...values.to !== void 0 ? { to: values.to } : {} });
|
|
5638
|
+
if (values.json) json3(result);
|
|
5639
|
+
else print([renderUpgrade(result, values.diff || result.status === "preview"), ...p.linked ? [style.warn(`! linked: the design system is your checkout ${p.linked}, not the config's source (youiyoux unlink to undo)`)] : []].join("\n"));
|
|
5640
|
+
return result.status === "blocked" ? 1 : 0;
|
|
5641
|
+
}
|
|
5451
5642
|
async function cmdInit(values) {
|
|
5452
5643
|
if (!values.design) throw new UsageError("youiyoux init --design <dir|package> (a design repo checkout, the directory holding youi.config.json, or the npm package that holds it)");
|
|
5453
5644
|
const root = values.project ?? process.cwd();
|
|
5454
5645
|
const design = await designArg(values.design, root);
|
|
5455
|
-
const result = await initProject({ root, ...design, schemaDir:
|
|
5646
|
+
const result = await initProject({ root, ...design, schemaDir: join26(TOOL_ROOT, "schema"), ...values.system ? { system: values.system } : {}, ...values.components ? { componentsDir: values.components } : {}, force: values.force });
|
|
5456
5647
|
if (!values.json) {
|
|
5457
5648
|
print(`${style.ok("created")} ${result.file}`);
|
|
5458
5649
|
for (const note of result.notes) print(style.dim(` \xB7 ${note}`));
|
|
@@ -5463,27 +5654,27 @@ async function cmdInit(values) {
|
|
|
5463
5654
|
}
|
|
5464
5655
|
async function cmdAdopt(values) {
|
|
5465
5656
|
const root = resolve15(values.project ?? process.cwd());
|
|
5466
|
-
if (await exists(
|
|
5657
|
+
if (await exists(join26(root, PROJECT_FILE))) throw new Error(`${root} already has ${PROJECT_FILE}: it follows a design system already (youiyoux sync updates it)`);
|
|
5467
5658
|
const plan = await planAdoption({ root, ...values.components ? { componentsDir: values.components } : {}, ...values.css ? { css: values.css } : {}, ...values.system ? { system: values.system } : {}, fork: values.fork });
|
|
5468
|
-
const taken = (await Promise.all(plan.files.map(async (f) => await exists(
|
|
5659
|
+
const taken = (await Promise.all(plan.files.map(async (f) => await exists(join26(root, f.path)) ? f.path : null))).filter((f) => f !== null);
|
|
5469
5660
|
if (taken.length > 0) throw new Error(`nothing was written: ${taken.slice(0, 5).join(", ")}${taken.length > 5 ? ` and ${taken.length - 5} more` : ""} already exist${taken.length === 1 ? "s" : ""}`);
|
|
5470
5661
|
if (values["dry-run"]) {
|
|
5471
5662
|
if (values.json) json3(plan);
|
|
5472
5663
|
else print([...adoptLines(plan, true), "", style.dim(`dry run: nothing written; would write ${plan.files.map((f) => f.path).join(", ")}${plan.stylesheet ? ` and change ${plan.stylesheet.path}` : ""}`)].join("\n"));
|
|
5473
5664
|
return 0;
|
|
5474
5665
|
}
|
|
5475
|
-
const stylesheet = plan.stylesheet ? await readFile10(
|
|
5666
|
+
const stylesheet = plan.stylesheet ? await readFile10(join26(root, plan.stylesheet.path), "utf8") : null;
|
|
5476
5667
|
try {
|
|
5477
|
-
for (const file of plan.files) await writeFileAtomic(
|
|
5478
|
-
if (plan.stylesheet) await writeFileAtomic(
|
|
5479
|
-
await initProject({ root, design: root, schemaDir:
|
|
5668
|
+
for (const file of plan.files) await writeFileAtomic(join26(root, file.path), file.content);
|
|
5669
|
+
if (plan.stylesheet) await writeFileAtomic(join26(root, plan.stylesheet.path), plan.stylesheet.content);
|
|
5670
|
+
await initProject({ root, design: root, schemaDir: join26(TOOL_ROOT, "schema"), system: plan.system.id, componentsDir: plan.componentsDir, outputs: { ...plan.outputs, targets: [...plan.outputs.targets], dark: [...plan.outputs.dark] }, tokenSources: plan.tokenSources });
|
|
5480
5671
|
await syncProject(await loadProject(root), { dryRun: true });
|
|
5481
5672
|
} catch (error) {
|
|
5482
|
-
for (const file of [...plan.files.map((f) => f.path), PROJECT_FILE]) await
|
|
5483
|
-
for (const folder of [...new Set(plan.files.map((f) => dirname13(f.path)))].sort((a, b) => b.length - a.length)) await rmdir3(
|
|
5484
|
-
await rmdir3(
|
|
5485
|
-
await rmdir3(
|
|
5486
|
-
if (plan.stylesheet && stylesheet !== null) await writeFileAtomic(
|
|
5673
|
+
for (const file of [...plan.files.map((f) => f.path), PROJECT_FILE]) await rm7(join26(root, file), { force: true });
|
|
5674
|
+
for (const folder of [...new Set(plan.files.map((f) => dirname13(f.path)))].sort((a, b) => b.length - a.length)) await rmdir3(join26(root, folder)).catch(() => void 0);
|
|
5675
|
+
await rmdir3(join26(root, "design/components")).catch(() => void 0);
|
|
5676
|
+
await rmdir3(join26(root, "design")).catch(() => void 0);
|
|
5677
|
+
if (plan.stylesheet && stylesheet !== null) await writeFileAtomic(join26(root, plan.stylesheet.path), stylesheet);
|
|
5487
5678
|
throw new Error(`adopt was undone, nothing kept: ${error instanceof Error ? error.message : String(error)}`);
|
|
5488
5679
|
}
|
|
5489
5680
|
if (!values.json) print([...adoptLines(plan), ""].join("\n"));
|
|
@@ -5557,7 +5748,7 @@ async function cmdUnlink(values) {
|
|
|
5557
5748
|
}
|
|
5558
5749
|
async function designArg(value, root) {
|
|
5559
5750
|
if (existsSync5(resolve15(value)) || !PACKAGE_NAME.test(value)) return { design: value };
|
|
5560
|
-
return { design: await designRootOf({ package: value },
|
|
5751
|
+
return { design: await designRootOf({ package: value }, join26(resolve15(root), PROJECT_FILE), root), package: value };
|
|
5561
5752
|
}
|
|
5562
5753
|
async function cmdBuild(values) {
|
|
5563
5754
|
const root = resolve15(values.design ?? process.cwd());
|
|
@@ -5566,10 +5757,10 @@ async function cmdBuild(values) {
|
|
|
5566
5757
|
const output = OutputConfig.parse({ cssVarPrefix: values.prefix ?? "youi", targets: ["css-vars", "tailwind-v4", "ts", "react-native"] });
|
|
5567
5758
|
const started = performance.now();
|
|
5568
5759
|
const built = await buildTokens(root, system.config, output, { contracts: system.components.map((c) => c.contract) });
|
|
5569
|
-
const out = resolve15(values.out ??
|
|
5570
|
-
const boundary = values.out ? out :
|
|
5571
|
-
if (!within(boundary, out) || built.files.some((file) => !within(out,
|
|
5572
|
-
for (const file of built.files) await writeFileAtomic(
|
|
5760
|
+
const out = resolve15(values.out ?? join26(root, "build", system.config.id));
|
|
5761
|
+
const boundary = values.out ? out : join26(root, "build");
|
|
5762
|
+
if (!within(boundary, out) || built.files.some((file) => !within(out, join26(out, file.path)))) throw new Error(`Cannot build system ${JSON.stringify(system.config.id)}: an output path leaves the output directory.`);
|
|
5763
|
+
for (const file of built.files) await writeFileAtomic(join26(out, file.path), file.content);
|
|
5573
5764
|
if (values.json) json3({ out, files: built.files.map((f) => f.path), tokens: built.tokens.length });
|
|
5574
5765
|
else print(`${style.ok("built")} ${plural(built.tokens.length, "token")} \u2192 ${built.files.map((f) => f.path).join(", ")} ${style.dim(`in ${out} (${ms(performance.now() - started)})`)}`);
|
|
5575
5766
|
return 0;
|
|
@@ -5594,16 +5785,16 @@ async function cmdParity(values) {
|
|
|
5594
5785
|
async function cmdSchema(values) {
|
|
5595
5786
|
const schemas = renderJsonSchemas();
|
|
5596
5787
|
if (values.check) {
|
|
5597
|
-
const dir =
|
|
5788
|
+
const dir = join26(values.design ? resolve15(values.design) : TOOL_ROOT, "schema");
|
|
5598
5789
|
const stale = [];
|
|
5599
|
-
for (const { file, content } of schemas) if (await readFile10(
|
|
5790
|
+
for (const { file, content } of schemas) if (await readFile10(join26(dir, file), "utf8").catch(() => null) !== content) stale.push(file);
|
|
5600
5791
|
if (values.json) json3({ dir, stale });
|
|
5601
5792
|
else print(stale.length === 0 ? `${style.ok("\u2713")} ${dir} matches this youi's schemas` : `${style.error("\u2716")} out of date in ${dir}: ${stale.join(", ")}; run youiyoux schema --write${values.design ? " --design <dir>" : ""}`);
|
|
5602
5793
|
return stale.length === 0 ? 0 : 1;
|
|
5603
5794
|
}
|
|
5604
5795
|
if (values.write) {
|
|
5605
5796
|
const root = values.design ? resolve15(values.design) : TOOL_ROOT;
|
|
5606
|
-
for (const { file, content } of schemas) await writeFileAtomic(
|
|
5797
|
+
for (const { file, content } of schemas) await writeFileAtomic(join26(root, "schema", file), content);
|
|
5607
5798
|
print(`${style.ok("wrote")} ${schemas.map((s) => s.file).join(", ")}`);
|
|
5608
5799
|
} else json3(Object.fromEntries(schemas.map((s) => [s.file, JSON.parse(s.content)])));
|
|
5609
5800
|
return 0;
|
|
@@ -5626,7 +5817,7 @@ async function cmdHooks(values, positionals) {
|
|
|
5626
5817
|
if (action !== "install") throw new UsageError("youiyoux hooks install [--claude] [--git] [--ci [--diff]] [--strict] or youiyoux hooks run claude|pre-commit");
|
|
5627
5818
|
const p = await loadCheckProject(values.project ?? process.cwd(), loadOptions(values), !values.project);
|
|
5628
5819
|
if (values.ci && !configured(p)) throw new UsageError("Run youiyoux init --design <dir> before installing the pinned CI workflow; repo-mode CI can run youiyoux check --diff <base> --strict directly");
|
|
5629
|
-
const target = { ...hookTarget(values), project: p.root, ...configured(p) && p.configFile && p.configFile !==
|
|
5820
|
+
const target = { ...hookTarget(values), project: p.root, ...configured(p) && p.configFile && p.configFile !== join26(p.root, PROJECT_FILE) ? { config: p.configFile } : {}, ...values.root !== void 0 ? { root: p.root } : {} };
|
|
5630
5821
|
const all = !values.claude && !values.git && !values.ci;
|
|
5631
5822
|
const results = [];
|
|
5632
5823
|
if (values.claude || all) results.push({ kind: "Claude Code", ...await installClaudeHook(await repoRootOf(p.root), hookCommand(TOOL_ROOT, "claude", target)) });
|
|
@@ -5645,7 +5836,7 @@ async function cmdAgents(values, positionals) {
|
|
|
5645
5836
|
const repoRoot = await repoRootOf(projectRoot);
|
|
5646
5837
|
const target = { project: projectRoot, ...values.config ? { config: resolve15(values.config) } : {}, ...values.design ? { design: resolve15(values.design) } : {}, ...values.root !== void 0 ? { root: resolve15(values.root || ".") } : {} };
|
|
5647
5838
|
const server = mcpCommand(TOOL_ROOT, target);
|
|
5648
|
-
const system = existsSync5(resolve15(values.config ??
|
|
5839
|
+
const system = existsSync5(resolve15(values.config ?? join26(projectRoot, PROJECT_FILE))) ? await project(values) : null;
|
|
5649
5840
|
const claudeServer = system && system.root === repoRoot ? { command: "node", args: mcpArgs(system) } : relativeTo(repoRoot, server);
|
|
5650
5841
|
const both = !values.claude && !values.codex;
|
|
5651
5842
|
const results = [];
|
|
@@ -5787,7 +5978,7 @@ async function cmdRequests(values, positionals) {
|
|
|
5787
5978
|
const usage = "youiyoux requests [--status open|addressed|closed|all] [--route r] or youiyoux requests show <id> | reply <id> --message <text> | addressed <id> --message <what you changed>";
|
|
5788
5979
|
const [action, id, ...rest] = positionals;
|
|
5789
5980
|
if (rest.length > 0) throw new UsageError(usage);
|
|
5790
|
-
const { RequestStore, requestBrief } = await import("./src-
|
|
5981
|
+
const { RequestStore, requestBrief } = await import("./src-6SNQVIZS.js");
|
|
5791
5982
|
const { project: project2, root } = await product(values);
|
|
5792
5983
|
const store = new RequestStore(root, project2?.config.id ?? basename5(root));
|
|
5793
5984
|
const agent = { kind: "agent", name: "youiyoux CLI" };
|
|
@@ -5820,8 +6011,8 @@ async function cmdScreens(values, positionals, io) {
|
|
|
5820
6011
|
if (!["capture", "login"].includes(positionals[0] ?? "") || positionals.length > 1 || !values.base) throw new UsageError(usage);
|
|
5821
6012
|
const { root } = await product(values);
|
|
5822
6013
|
if (positionals[0] === "login") return screensLogin(values.base, values["storage-state"] ? resolve15(values["storage-state"]) : sessionFile(root), io);
|
|
5823
|
-
const dir = resolve15(values.out ??
|
|
5824
|
-
if (!existsSync5(
|
|
6014
|
+
const dir = resolve15(values.out ?? join26(root, ".youi/screens"));
|
|
6015
|
+
if (!existsSync5(join26(dir, "screens.json"))) {
|
|
5825
6016
|
process.stderr.write(`${style.error("\u2716")} no screens.json in ${dir}: list the routes to capture there, as {"schema":"youiyoux.screens/v1","project":"<name>","source":"<what the app is>","capturedAt":"","viewport":{"width":1440,"height":900},"screens":[{"route":"/","path":"/"}]}
|
|
5826
6017
|
`);
|
|
5827
6018
|
return 1;
|
|
@@ -5886,7 +6077,7 @@ async function cmdReport(values, positionals, io) {
|
|
|
5886
6077
|
return result.code;
|
|
5887
6078
|
}
|
|
5888
6079
|
async function cmdMcp(values) {
|
|
5889
|
-
const { startStdioServer } = await import("./src-
|
|
6080
|
+
const { startStdioServer } = await import("./src-75ODGHE3.js");
|
|
5890
6081
|
await startStdioServer({ projectRoot: values.project ?? process.cwd(), ...loadOptions(values), ...values.cache ? { discoverCache: values.cache } : {} });
|
|
5891
6082
|
return -1;
|
|
5892
6083
|
}
|
|
@@ -5961,6 +6152,7 @@ var COMMANDS = {
|
|
|
5961
6152
|
rules: cmdRules,
|
|
5962
6153
|
plan: cmdPlan,
|
|
5963
6154
|
migrate: cmdMigrate,
|
|
6155
|
+
upgrade: cmdUpgrade,
|
|
5964
6156
|
init: cmdInit,
|
|
5965
6157
|
sync: cmdSync,
|
|
5966
6158
|
scan: cmdScan,
|
|
@@ -6012,7 +6204,7 @@ ${HELP}
|
|
|
6012
6204
|
}
|
|
6013
6205
|
return guarded(() => handler(located(command2, parsed.values), rest, io));
|
|
6014
6206
|
}
|
|
6015
|
-
var IN_A_PRODUCT = /* @__PURE__ */ new Set(["system", "link", "unlink", "show", "where", "bom", "check", "baseline", "rules", "plan", "migrate", "sync", "scan", "watch", "hooks", "agents", "mcp", "ui", "library", "render", "screens", "requests"]);
|
|
6207
|
+
var IN_A_PRODUCT = /* @__PURE__ */ new Set(["system", "link", "unlink", "show", "where", "bom", "check", "baseline", "rules", "plan", "migrate", "upgrade", "sync", "scan", "watch", "hooks", "agents", "mcp", "ui", "library", "render", "screens", "requests"]);
|
|
6016
6208
|
var IN_A_DESIGN_REPO = /* @__PURE__ */ new Set(["build", "parity"]);
|
|
6017
6209
|
function located(command2, values, cwd = process.cwd()) {
|
|
6018
6210
|
if (IN_A_PRODUCT.has(command2) && values.project === void 0 && values.config === void 0 && values.root === void 0) {
|
|
@@ -3,7 +3,7 @@ import { createRequire as __youiRequire } from "node:module"; import { dirname a
|
|
|
3
3
|
// src/hub-packages.js
|
|
4
4
|
var PACKAGES = {
|
|
5
5
|
core: () => import("./src-BYNWPNRT.js"),
|
|
6
|
-
scanner: () => import("./src-
|
|
6
|
+
scanner: () => import("./src-XTNHB65M.js"),
|
|
7
7
|
discover: () => import("./src-DPFJ4S2N.js"),
|
|
8
8
|
tokens: () => import("./src-PURAHRCR.js")
|
|
9
9
|
};
|
|
@@ -751,7 +751,13 @@ async function loadProject(root, options = {}) {
|
|
|
751
751
|
const productRoot = options.productRoot !== void 0 ? resolve2(options.productRoot || ".") : config.root ? fromConfig(config.root) : resolve2(root);
|
|
752
752
|
if (!await isDirectory2(productRoot)) throw new ProjectRootError(`product root ${productRoot} is not a directory (config ${configFile}); ${ROOT_HINT}`);
|
|
753
753
|
const linked = options.designRoot ? null : await linkedDesign(productRoot);
|
|
754
|
-
|
|
754
|
+
if (options.ref !== void 0) {
|
|
755
|
+
if (options.designRoot || linked) throw new Error(`the design system is ${options.designRoot ? "the --design folder" : `your checkout ${linked}`}, not the config's source: check out ${options.ref} there${linked ? ", or youiyoux unlink" : ""}`);
|
|
756
|
+
if ("package" in config.source) throw new Error(`${config.source.package} is an npm package: install the version you want (npm install ${config.source.package}@<version>), then run this again without --to`);
|
|
757
|
+
if ("path" in config.source) throw new Error(`the design system is the folder ${config.source.path}: check out ${options.ref} there, then run this again without --to`);
|
|
758
|
+
}
|
|
759
|
+
const source = options.ref !== void 0 && "git" in config.source ? { ...config.source, ref: options.ref } : config.source;
|
|
760
|
+
const located = options.designRoot || linked ? { root: resolve2(options.designRoot || linked), commit: null } : await locateDesign(source, configFile, productRoot, { refresh: options.refreshDesign || options.ref !== void 0 });
|
|
755
761
|
const repo = await loadDesignRepo(located.root);
|
|
756
762
|
return {
|
|
757
763
|
root: productRoot,
|
|
@@ -2408,7 +2414,7 @@ async function parseAll(project, files, overrides, parse3) {
|
|
|
2408
2414
|
}
|
|
2409
2415
|
async function scanProject(project, options = {}) {
|
|
2410
2416
|
const started = performance.now();
|
|
2411
|
-
const overrides = options.overrides
|
|
2417
|
+
const overrides = { ...project.staged, ...options.overrides };
|
|
2412
2418
|
const { cache } = options;
|
|
2413
2419
|
cache?.beginScan();
|
|
2414
2420
|
const parse3 = cache?.parse ?? parseModule;
|
|
@@ -57,8 +57,8 @@ import {
|
|
|
57
57
|
validateContent,
|
|
58
58
|
validateLibraryContent,
|
|
59
59
|
validateStyleContent
|
|
60
|
-
} from "./chunk-
|
|
61
|
-
import "./chunk-
|
|
60
|
+
} from "./chunk-OCZJ3JGH.js";
|
|
61
|
+
import "./chunk-X2YYMHR4.js";
|
|
62
62
|
import "./chunk-42YJX3W5.js";
|
|
63
63
|
import "./chunk-FLBRX6Y3.js";
|
|
64
64
|
import "./chunk-DWYDHVLZ.js";
|
|
@@ -2,7 +2,7 @@ import { createRequire as __youiRequire } from "node:module"; import { dirname a
|
|
|
2
2
|
import {
|
|
3
3
|
RequestStore,
|
|
4
4
|
requestBrief
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-OCZJ3JGH.js";
|
|
6
6
|
import {
|
|
7
7
|
PROJECT_FILE,
|
|
8
8
|
ScanCache,
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
shotsText,
|
|
31
31
|
tokenRows,
|
|
32
32
|
whereUsed
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-X2YYMHR4.js";
|
|
34
34
|
import "./chunk-42YJX3W5.js";
|
|
35
35
|
import {
|
|
36
36
|
SHADCN_SLOTS,
|
package/dist/hub-previews.js
CHANGED
|
@@ -16,8 +16,8 @@ import {
|
|
|
16
16
|
selectCandidates,
|
|
17
17
|
thumbsDir,
|
|
18
18
|
writeThumbIndex
|
|
19
|
-
} from "./chunks/chunk-
|
|
20
|
-
import "./chunks/chunk-
|
|
19
|
+
} from "./chunks/chunk-3RP664IP.js";
|
|
20
|
+
import "./chunks/chunk-T3KNPVQG.js";
|
|
21
21
|
import "./chunks/chunk-FVVL5JCY.js";
|
|
22
22
|
import "./chunks/chunk-DWYDHVLZ.js";
|
|
23
23
|
import "./chunks/chunk-WNTS7ZO4.js";
|
package/dist/hub-server.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRequire as __youiRequire } from "node:module"; import { dirname as __youiDir } from "node:path"; import { fileURLToPath as __youiPath } from "node:url"; const require = __youiRequire(import.meta.url); const __youiDirname = __youiDir(__youiPath(import.meta.url));
|
|
3
3
|
import {
|
|
4
4
|
discoverThumbsMiddleware
|
|
5
|
-
} from "./chunks/chunk-
|
|
5
|
+
} from "./chunks/chunk-3RP664IP.js";
|
|
6
6
|
import {
|
|
7
7
|
isLocalHost,
|
|
8
8
|
loadPackage,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
readTryIndex,
|
|
11
11
|
send,
|
|
12
12
|
tryMiddleware
|
|
13
|
-
} from "./chunks/chunk-
|
|
13
|
+
} from "./chunks/chunk-T3KNPVQG.js";
|
|
14
14
|
import "./chunks/chunk-FVVL5JCY.js";
|
|
15
15
|
import "./chunks/chunk-DWYDHVLZ.js";
|
|
16
16
|
import "./chunks/chunk-WNTS7ZO4.js";
|
package/dist/hub-snapshot.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire as __youiRequire } from "node:module"; import { dirname a
|
|
|
3
3
|
import {
|
|
4
4
|
loadPackage,
|
|
5
5
|
tryProject
|
|
6
|
-
} from "./chunks/chunk-
|
|
6
|
+
} from "./chunks/chunk-T3KNPVQG.js";
|
|
7
7
|
import "./chunks/chunk-FVVL5JCY.js";
|
|
8
8
|
import "./chunks/chunk-WNTS7ZO4.js";
|
|
9
9
|
|
package/dist/youi.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { createRequire as __youiRequire } from "node:module"; import { dirname as __youiDir } from "node:path"; import { fileURLToPath as __youiPath } from "node:url"; const require = __youiRequire(import.meta.url); const __youiDirname = __youiDir(__youiPath(import.meta.url));
|
|
3
3
|
import {
|
|
4
4
|
main
|
|
5
|
-
} from "./chunks/chunk-
|
|
6
|
-
import "./chunks/chunk-
|
|
5
|
+
} from "./chunks/chunk-75DBKEAH.js";
|
|
6
|
+
import "./chunks/chunk-X2YYMHR4.js";
|
|
7
7
|
import "./chunks/chunk-42YJX3W5.js";
|
|
8
8
|
import "./chunks/chunk-HDJ2TOWZ.js";
|
|
9
9
|
import "./chunks/chunk-6GITMASZ.js";
|
package/dist/youiyoux.js
CHANGED
|
@@ -3,8 +3,8 @@ import { createRequire as __youiRequire } from "node:module"; import { dirname a
|
|
|
3
3
|
import {
|
|
4
4
|
COMMAND_NAMES,
|
|
5
5
|
main
|
|
6
|
-
} from "./chunks/chunk-
|
|
7
|
-
import "./chunks/chunk-
|
|
6
|
+
} from "./chunks/chunk-75DBKEAH.js";
|
|
7
|
+
import "./chunks/chunk-X2YYMHR4.js";
|
|
8
8
|
import "./chunks/chunk-42YJX3W5.js";
|
|
9
9
|
import "./chunks/chunk-HDJ2TOWZ.js";
|
|
10
10
|
import "./chunks/chunk-6GITMASZ.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "youiyoux",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Your agent rebuilds components you already have. youiyoux catches it: npx youiyoux turns any repo into a shareable report of near-duplicate components, hardcoded token values and off-library imports, with the fixes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
"typescript": "6.0.3"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@youiyoux/cli": "0.1.
|
|
50
|
-
"@youiyoux/core": "0.1.
|
|
51
|
-
"@youiyoux/scanner": "0.1.
|
|
49
|
+
"@youiyoux/cli": "0.1.10",
|
|
50
|
+
"@youiyoux/core": "0.1.10",
|
|
51
|
+
"@youiyoux/scanner": "0.1.10"
|
|
52
52
|
},
|
|
53
53
|
"exports": {
|
|
54
54
|
"./package.json": "./package.json"
|