youiyoux 0.1.19 → 0.1.21
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/README.md +2 -0
- package/dist/chunks/{chunk-NG73FB4O.js → chunk-55I4SXOA.js} +1 -1
- package/dist/chunks/{chunk-OE4RYJOS.js → chunk-ALD2RX3X.js} +1 -1
- package/dist/chunks/{chunk-DHZDMZXE.js → chunk-FYG6USCG.js} +36 -17
- package/dist/chunks/{chunk-AFEQZT2N.js → chunk-O77MKELR.js} +1 -1
- package/dist/chunks/{chunk-75LXBAYB.js → chunk-RQUTV7SO.js} +79 -9
- package/dist/chunks/{chunk-2F2HM7FE.js → chunk-ZXINIRJ5.js} +3 -3
- package/dist/chunks/{ingest-X4MIF5F6.js → ingest-4C3TRSBA.js} +3 -3
- package/dist/chunks/{src-Q3ZJHEUQ.js → src-DUBN6O7T.js} +1 -1
- package/dist/chunks/{src-LGHUKRL2.js → src-JTMKM6KB.js} +2 -2
- package/dist/chunks/{src-VSWKGVFT.js → src-LP3MFGA4.js} +2 -2
- 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 +3 -3
- package/dist/youiyoux.js +3 -3
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ No config, no account. You get:
|
|
|
16
16
|
- `youiyoux-card.png`: a 1200×630 card with the headline numbers.
|
|
17
17
|
- `youiyoux-summary.md`: paste it into a PR or issue.
|
|
18
18
|
|
|
19
|
+
New to it? [Getting started](https://github.com/ap9000/youiyoux/blob/main/docs/getting-started.md): the report, the top fix, your agent and CI, in five steps.
|
|
20
|
+
|
|
19
21
|
## For your agent
|
|
20
22
|
|
|
21
23
|
```sh
|
|
@@ -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-AXF5XUQE.js"),
|
|
6
|
-
scanner: () => import("./src-
|
|
6
|
+
scanner: () => import("./src-DUBN6O7T.js"),
|
|
7
7
|
discover: () => import("./src-ULAQV67E.js"),
|
|
8
8
|
tokens: () => import("./src-HBKEBCH6.js")
|
|
9
9
|
};
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
startRuleEditor,
|
|
10
10
|
style,
|
|
11
11
|
truncate
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZXINIRJ5.js";
|
|
13
13
|
import {
|
|
14
14
|
BASELINE_FILE,
|
|
15
15
|
DEFAULT_EXCLUDE,
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
vendoredPath,
|
|
65
65
|
whereUsed,
|
|
66
66
|
withFile
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-RQUTV7SO.js";
|
|
68
68
|
import {
|
|
69
69
|
escapingLinks,
|
|
70
70
|
within
|
|
@@ -1382,6 +1382,8 @@ async function themeTokens(root, modules) {
|
|
|
1382
1382
|
const theme = await buildTheme(root, sheets, false);
|
|
1383
1383
|
const tokens = [];
|
|
1384
1384
|
const byVar = /* @__PURE__ */ new Map();
|
|
1385
|
+
const themeKeys = /* @__PURE__ */ new Map();
|
|
1386
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1385
1387
|
for (const [name, raw] of theme.declared) {
|
|
1386
1388
|
const value = substituteVars(raw, (key2) => theme.variable(key2));
|
|
1387
1389
|
if (value === null) continue;
|
|
@@ -1390,11 +1392,16 @@ async function themeTokens(root, modules) {
|
|
|
1390
1392
|
const px = kind ? theme.length(value) : null;
|
|
1391
1393
|
if (!color && px === null) continue;
|
|
1392
1394
|
const light = color ?? { value: px, unit: "px" };
|
|
1393
|
-
const
|
|
1395
|
+
const group = color ? "color" : kind;
|
|
1396
|
+
const short = `${group}.${name.slice(2).replace(new RegExp(`^${group}-`), "")}`;
|
|
1397
|
+
const id = ids.has(short) ? `${group}.${name.slice(2)}` : short;
|
|
1398
|
+
ids.add(id);
|
|
1399
|
+
const token = { id, type: color ? "color" : "dimension", cssName: name.slice(2), light, dark: light };
|
|
1394
1400
|
tokens.push(token);
|
|
1395
1401
|
byVar.set(name, token);
|
|
1402
|
+
if (theme.utilities.has(name)) themeKeys.set(id, [name.slice(2)]);
|
|
1396
1403
|
}
|
|
1397
|
-
return { prefix: "", tokens, byVar, themeKeys
|
|
1404
|
+
return { prefix: "", tokens, byVar, themeKeys };
|
|
1398
1405
|
}
|
|
1399
1406
|
async function runRepoCheck(project2, change) {
|
|
1400
1407
|
const target = await loadInventoryTarget(project2.root);
|
|
@@ -1729,7 +1736,7 @@ function renderDiffText(result) {
|
|
|
1729
1736
|
lines.push("");
|
|
1730
1737
|
if (diff.findings.length > 0) lines.push(style.error(`\u2716 ${plural(diff.findings.length, "finding")} in this change: apply each fix (\u2192), then run \`youiyoux check --diff\` again`));
|
|
1731
1738
|
else if (gaps.length > 0) lines.push(style.warn("! Not a pass: parts of this change could not be checked (above). Fix what could not be read, then run `youiyoux check --diff` again"));
|
|
1732
|
-
else if (diff.files.length === 0) lines.push(style.ok(`\u2713 No checked files changed against ${diff.base}: nothing to check. Compare with a branch: youiyoux check --diff main`));
|
|
1739
|
+
else if (diff.files.length === 0) lines.push(style.ok(`\u2713 No checked files changed against ${diff.base}: nothing to check${diff.base === "HEAD" ? ". Compare with a branch: youiyoux check --diff main" : ""}`));
|
|
1733
1740
|
else lines.push(style.ok(`\u2713 No drift in this change: ${plural(diff.files.length, "file")} checked against ${diff.base}. Nothing to fix`));
|
|
1734
1741
|
return lines.join("\n");
|
|
1735
1742
|
}
|
|
@@ -1747,9 +1754,10 @@ function diffJson(result) {
|
|
|
1747
1754
|
identity: result.identity
|
|
1748
1755
|
};
|
|
1749
1756
|
}
|
|
1750
|
-
function githubDiffAnnotations(result, prefix) {
|
|
1751
|
-
const
|
|
1752
|
-
|
|
1757
|
+
function githubDiffAnnotations(result, prefix, strict) {
|
|
1758
|
+
const level = (severity) => strict && severity === "error" ? "error" : "warning";
|
|
1759
|
+
const lines = (result.diff?.findings ?? []).map((f) => command(level(f.severity), `${f.message} Fix: ${f.fix}`, { file: `${prefix}${f.file}`, line: f.line, col: f.column, title: `youi ${kindOf(f)}` }));
|
|
1760
|
+
for (const gap of diffGaps(result)) lines.push(command(level("error"), `${gap}; a clean result here is not a pass`, { title: "youi incomplete" }));
|
|
1753
1761
|
return lines;
|
|
1754
1762
|
}
|
|
1755
1763
|
function githubDiffSummary(result) {
|
|
@@ -3409,7 +3417,7 @@ async function projectStatus(project2, cwd = process.cwd()) {
|
|
|
3409
3417
|
const comparison = check.baseline?.comparison;
|
|
3410
3418
|
const counted = comparison ? [...comparison.new, ...comparison.regressed] : check.violations;
|
|
3411
3419
|
const usages = check.scan.report.usages;
|
|
3412
|
-
const { RequestStore } = await import("./src-
|
|
3420
|
+
const { RequestStore } = await import("./src-LP3MFGA4.js");
|
|
3413
3421
|
const requests = await new RequestStore(project2.root, project2.config.id).list();
|
|
3414
3422
|
const status = {
|
|
3415
3423
|
id: project2.config.id,
|
|
@@ -4735,17 +4743,23 @@ async function modulesOf(project2, target, failed3) {
|
|
|
4735
4743
|
}
|
|
4736
4744
|
return modules;
|
|
4737
4745
|
}
|
|
4746
|
+
function groupKey(finding3) {
|
|
4747
|
+
if (finding3.kind === "off-library") return finding3.message;
|
|
4748
|
+
if (finding3.kind !== "hardcoded-value") return finding3.fix;
|
|
4749
|
+
const { word, value, tokens } = hardcodedValue(finding3);
|
|
4750
|
+
return `${word}\0${value}\0${tokens}`;
|
|
4751
|
+
}
|
|
4738
4752
|
async function grouped(project2, found, lines, describe) {
|
|
4739
4753
|
const groups = /* @__PURE__ */ new Map();
|
|
4740
4754
|
for (const finding3 of found) {
|
|
4741
|
-
const key2 = `${finding3.kind}\0${finding3
|
|
4755
|
+
const key2 = `${finding3.kind}\0${groupKey(finding3)}`;
|
|
4742
4756
|
groups.set(key2, [...groups.get(key2) ?? [], finding3]);
|
|
4743
4757
|
}
|
|
4744
4758
|
const findings2 = [];
|
|
4745
4759
|
for (const list of groups.values()) {
|
|
4746
4760
|
const first = list[0];
|
|
4747
4761
|
const sites = await Promise.all(list.slice(0, SITES_PER_FINDING).map((f) => lines.site(`${repoPath(project2.dir, f.file)}:${f.line}`, repoPath(project2.dir, f.file), f.line)));
|
|
4748
|
-
const { title, next: next2 } = describe(first, list.length);
|
|
4762
|
+
const { title, next: next2 } = describe(first, list.length, list);
|
|
4749
4763
|
findings2.push({ kind: first.kind, project: project2.dir, count: list.length, sites, title, detail: null, next: next2 });
|
|
4750
4764
|
}
|
|
4751
4765
|
return findings2.sort((a, b) => b.count - a.count || a.title.localeCompare(b.title));
|
|
@@ -4812,9 +4826,14 @@ async function analyseProject(project2, index, inventory, inventoryError, worksp
|
|
|
4812
4826
|
if (tokens.tokens.length === 0) notes.push("No theme variables (CSS custom properties or Tailwind @theme) were found, so hardcoded values had nothing to be compared with");
|
|
4813
4827
|
const usage = tokenUsage(modules);
|
|
4814
4828
|
const found = (await Promise.all(modules.map((module) => reportTokens(module, tokens, usage)))).flat();
|
|
4815
|
-
hardcoded = await grouped(project2, found, lines, (first, count) => {
|
|
4829
|
+
hardcoded = await grouped(project2, found, lines, (first, count, list) => {
|
|
4816
4830
|
const { word, value, tokens: names } = hardcodedValue(first);
|
|
4817
|
-
|
|
4831
|
+
const fixes = [...new Map(list.map((f) => [f.fix, f.text]))];
|
|
4832
|
+
const tail = / \([^()]*\)$/.exec(first.fix)?.[0] ?? "";
|
|
4833
|
+
const shared = tail !== "" && fixes.every(([fix]) => fix.endsWith(tail));
|
|
4834
|
+
const each = fixes.slice(0, 3).map(([fix, text], i) => `${(shared ? fix.slice(0, -tail.length) : fix).replace(i > 0 ? /^use / : /^$/, "")} for ${text}`);
|
|
4835
|
+
const next2 = fixes.length === 1 ? `${sentence(first.fix)} in each place` : `${sentence(each.join(", "))}${fixes.length > 3 ? ", \u2026" : ""}${shared ? tail : ""}`;
|
|
4836
|
+
return { title: `${sentence(word)} ${value} is hardcoded in ${plural(count, "place")}; the theme already has it as ${names}`, next: next2 };
|
|
4818
4837
|
});
|
|
4819
4838
|
} catch (error) {
|
|
4820
4839
|
incomplete.push(`Hardcoded values were not checked (${errorText(error)}); run ${NPX} check --diff to see why`);
|
|
@@ -5965,7 +5984,7 @@ async function cmdCheckDiff(values, positionals, p, format) {
|
|
|
5965
5984
|
const result = configured(p) ? await runCheck(p, { ...checkScope(values, positionals), diff: change }) : await runRepoCheck(p, change);
|
|
5966
5985
|
if (format === "json") json3(diffJson(result));
|
|
5967
5986
|
else if (format === "github") {
|
|
5968
|
-
for (const line of githubDiffAnnotations(result, await repoPrefix(p.root))) print(line);
|
|
5987
|
+
for (const line of githubDiffAnnotations(result, await repoPrefix(p.root), values.strict)) print(line);
|
|
5969
5988
|
print(renderDiffText(result));
|
|
5970
5989
|
if (process.env.GITHUB_STEP_SUMMARY) await appendFile2(process.env.GITHUB_STEP_SUMMARY, githubDiffSummary(result));
|
|
5971
5990
|
} else print(renderDiffText(result));
|
|
@@ -6048,7 +6067,7 @@ async function cmdLibrary(values, positionals) {
|
|
|
6048
6067
|
return 0;
|
|
6049
6068
|
}
|
|
6050
6069
|
if (action === "ingest" && query && positionals.length === 2) {
|
|
6051
|
-
const { fileIngestDraft, readLink, renderIngest } = await import("./ingest-
|
|
6070
|
+
const { fileIngestDraft, readLink, renderIngest } = await import("./ingest-4C3TRSBA.js");
|
|
6052
6071
|
const p = values.draft ? await project(values) : null;
|
|
6053
6072
|
const reading = await readLink(query, { allowLocal: true });
|
|
6054
6073
|
const filed = p ? await fileIngestDraft(p, reading, values.state) : null;
|
|
@@ -6507,7 +6526,7 @@ async function cmdRequests(values, positionals) {
|
|
|
6507
6526
|
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>";
|
|
6508
6527
|
const [action, id, ...rest] = positionals;
|
|
6509
6528
|
if (rest.length > 0) throw new UsageError(usage);
|
|
6510
|
-
const { RequestStore, requestBrief } = await import("./src-
|
|
6529
|
+
const { RequestStore, requestBrief } = await import("./src-LP3MFGA4.js");
|
|
6511
6530
|
const { project: project2, root } = await product(values);
|
|
6512
6531
|
const store = new RequestStore(root, project2?.config.id ?? basename5(root));
|
|
6513
6532
|
const agent = { kind: "agent", name: "youiyoux CLI" };
|
|
@@ -6606,7 +6625,7 @@ async function cmdReport(values, positionals, io) {
|
|
|
6606
6625
|
return result.code;
|
|
6607
6626
|
}
|
|
6608
6627
|
async function cmdMcp(values) {
|
|
6609
|
-
const { startStdioServer } = await import("./src-
|
|
6628
|
+
const { startStdioServer } = await import("./src-JTMKM6KB.js");
|
|
6610
6629
|
await startStdioServer({ projectRoot: values.project ?? process.cwd(), ...loadOptions(values), ...values.cache ? { discoverCache: values.cache } : {} });
|
|
6611
6630
|
return -1;
|
|
6612
6631
|
}
|
|
@@ -1224,13 +1224,16 @@ var Theme = class {
|
|
|
1224
1224
|
/** Project declarations only: excludes implicit Tailwind defaults. */
|
|
1225
1225
|
declared;
|
|
1226
1226
|
forms;
|
|
1227
|
+
/** Declared variables Tailwind makes utilities from (`--color-muted` → `text-muted`): an `@theme` block's, or the Tailwind config's. */
|
|
1228
|
+
utilities;
|
|
1227
1229
|
vars;
|
|
1228
|
-
constructor(vars, tailwind, warnings, declared = /* @__PURE__ */ new Map(), forms = null) {
|
|
1230
|
+
constructor(vars, tailwind, warnings, declared = /* @__PURE__ */ new Map(), forms = null, utilities = /* @__PURE__ */ new Set()) {
|
|
1229
1231
|
this.vars = vars;
|
|
1230
1232
|
this.declared = declared;
|
|
1231
1233
|
this.tailwind = tailwind;
|
|
1232
1234
|
this.warnings = warnings;
|
|
1233
1235
|
this.forms = forms;
|
|
1236
|
+
this.utilities = utilities;
|
|
1234
1237
|
}
|
|
1235
1238
|
variable(name) {
|
|
1236
1239
|
return this.vars.get(name);
|
|
@@ -1399,17 +1402,20 @@ async function buildTheme(root, sheets, usesTailwindPackage) {
|
|
|
1399
1402
|
const version = v4 ? 4 : v3 || usesTailwindPackage ? 3 : null;
|
|
1400
1403
|
const vars = version ? defaults(version) : /* @__PURE__ */ new Map();
|
|
1401
1404
|
const declared = new Map(config.vars);
|
|
1405
|
+
const utilities = new Set(version ? config.vars.keys() : []);
|
|
1402
1406
|
for (const [name, value] of config.vars) vars.set(name, value);
|
|
1403
1407
|
for (const sheet of sheets) {
|
|
1404
1408
|
for (const rule of sheet.rules) {
|
|
1405
|
-
|
|
1409
|
+
const scope = rule.preludes.length === 1 ? rule.preludes[0].replace(/\s+/g, " ") : null;
|
|
1410
|
+
if (!scope || !THEME_SCOPES.has(scope)) continue;
|
|
1406
1411
|
for (const declaration of rule.declarations) if (declaration.property.startsWith("--")) {
|
|
1407
1412
|
vars.set(declaration.property, declaration.value);
|
|
1408
1413
|
declared.set(declaration.property, declaration.value);
|
|
1414
|
+
if (version === 4 && scope.startsWith("@theme")) utilities.add(declaration.property);
|
|
1409
1415
|
}
|
|
1410
1416
|
}
|
|
1411
1417
|
}
|
|
1412
|
-
return new Theme(vars, version, config.warnings, declared, version ? await formsPluginOf(root, sheets, config.file) : null);
|
|
1418
|
+
return new Theme(vars, version, config.warnings, declared, version ? await formsPluginOf(root, sheets, config.file) : null, utilities);
|
|
1413
1419
|
}
|
|
1414
1420
|
|
|
1415
1421
|
// ../scanner/src/inventory/style.ts
|
|
@@ -1793,6 +1799,35 @@ function resolveClasses(classes, tag, theme, rules) {
|
|
|
1793
1799
|
// ../scanner/src/drift.ts
|
|
1794
1800
|
var cssVar = (token, index) => `var(${[...index.byVar].find(([, t]) => t === token)?.[0] ?? cssVariable(index.prefix, token.cssName)})`;
|
|
1795
1801
|
var tokenList = (tokens) => tokens.slice(0, 3).map((t) => t.id).join(" or ");
|
|
1802
|
+
var viewportOfWord = (word) => /^(phone|mobile|handset)$/.test(word) ? "narrow" : /^(tablet|desktop)$/.test(word) ? "wide" : null;
|
|
1803
|
+
var tokenViewport = (token) => token.id.split(/[.-]/).map(viewportOfWord).find((v) => v !== null) ?? null;
|
|
1804
|
+
function preludeViewports(preludes) {
|
|
1805
|
+
const found = /* @__PURE__ */ new Set();
|
|
1806
|
+
for (const prelude of preludes) {
|
|
1807
|
+
if (/^@media\b/.test(prelude) && /max-width|width\s*<=?/.test(prelude)) found.add("narrow");
|
|
1808
|
+
if (/^@media\b/.test(prelude) && /min-width|width\s*>=?/.test(prelude)) found.add("wide");
|
|
1809
|
+
for (const word of prelude.toLowerCase().match(/[a-z]+/g) ?? []) {
|
|
1810
|
+
const viewport = viewportOfWord(word);
|
|
1811
|
+
if (viewport) found.add(viewport);
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
return found;
|
|
1815
|
+
}
|
|
1816
|
+
function variantViewports(variants) {
|
|
1817
|
+
const found = /* @__PURE__ */ new Set();
|
|
1818
|
+
for (const variant of variants) {
|
|
1819
|
+
const viewport = viewportOfWord(variant) ?? (/^max-/.test(variant) ? "narrow" : /^(min-|@)?(sm|md|lg|xl|[2-9]xl)$/.test(variant) ? "wide" : null);
|
|
1820
|
+
if (viewport) found.add(viewport);
|
|
1821
|
+
}
|
|
1822
|
+
return found;
|
|
1823
|
+
}
|
|
1824
|
+
function fitting(tokens, viewports) {
|
|
1825
|
+
const own = tokens.filter((t) => {
|
|
1826
|
+
const v = tokenViewport(t);
|
|
1827
|
+
return v !== null && viewports.has(v);
|
|
1828
|
+
});
|
|
1829
|
+
return [...own, ...tokens.filter((t) => tokenViewport(t) === null)];
|
|
1830
|
+
}
|
|
1796
1831
|
function utilityBefore(lineText, column) {
|
|
1797
1832
|
return /(?:^|[\s"'`:])!?(-?[a-z][a-z0-9]*(?:-[a-z][a-z0-9]*)*)-\[$/.exec(lineText.slice(0, column - 1))?.[1] ?? null;
|
|
1798
1833
|
}
|
|
@@ -1823,11 +1858,12 @@ function arbitraryFindings(module, index, added) {
|
|
|
1823
1858
|
const offset = match.index + whole.indexOf(`${utility}-[`);
|
|
1824
1859
|
const at = offsetToPosition(text, offset, start);
|
|
1825
1860
|
if (!added(module.file, at.line)) continue;
|
|
1826
|
-
const
|
|
1861
|
+
const variants = whole.slice(0, whole.indexOf(`${utility}-[`));
|
|
1862
|
+
const tokens = fitting(arbitraryTokens(utility, value, index), variantViewports(variants.split(":")));
|
|
1827
1863
|
if (tokens.length === 0) continue;
|
|
1828
|
-
const utilities = tokenUtilities(utility, tokens, index);
|
|
1864
|
+
const utilities = tokenUtilities(utility, tokens, index).map((u) => `${variants}${u}`);
|
|
1829
1865
|
const kind = /^-?rounded/.test(utility) ? "radius" : utility === "text" ? "type" : "spacing";
|
|
1830
|
-
const fix = utilities.length > 0 ? `use ${utilities.slice(0, 2).join(" or ")} (${tokenList(tokens)}, ${cssVar(tokens[0], index)})` : `use ${utility}-[${cssVar(tokens[0], index)}] (${tokenList(tokens)})`;
|
|
1866
|
+
const fix = utilities.length > 0 ? `use ${utilities.slice(0, 2).join(" or ")} (${tokenList(tokens)}, ${cssVar(tokens[0], index)})` : `use ${variants}${utility}-[${cssVar(tokens[0], index)}] (${tokenList(tokens)})`;
|
|
1831
1867
|
findings.push({ kind: "hardcoded-value", file: module.file, ...at, text: `${utility}-[${value}]`, message: `Hardcoded ${kind} ${utility}-[${value}]: the token ${tokenList(tokens)} has this value.`, fix });
|
|
1832
1868
|
}
|
|
1833
1869
|
}
|
|
@@ -1845,9 +1881,10 @@ function cssDimensionFindings(module, index, isTokenSource, added) {
|
|
|
1845
1881
|
if (!added(module.file, declaration.line) || isTokenSource && declaration.property.startsWith("--")) continue;
|
|
1846
1882
|
const kind = CSS_DIMENSIONS.find(([pattern]) => pattern.test(declaration.property))?.[1];
|
|
1847
1883
|
if (!kind) continue;
|
|
1884
|
+
const viewports = preludeViewports(rule.preludes);
|
|
1848
1885
|
const matched = [];
|
|
1849
1886
|
const value = declaration.value.replace(/(^|[\s(,])(-?)(\d*\.?\d+)px\b/g, (whole, lead, sign, n) => {
|
|
1850
|
-
const token = dimensionTokens(kind, Number(n), index)[0];
|
|
1887
|
+
const token = fitting(dimensionTokens(kind, Number(n), index), viewports)[0];
|
|
1851
1888
|
if (!token || Number(n) === 0) return whole;
|
|
1852
1889
|
matched.push(token);
|
|
1853
1890
|
return `${lead}${sign ? `calc(-1 * ${cssVar(token, index)})` : cssVar(token, index)}`;
|
|
@@ -1900,7 +1937,6 @@ function nearDuplicates(input) {
|
|
|
1900
1937
|
const { inventory, added, importOf } = input;
|
|
1901
1938
|
const definitions = new Map(inventory.definitions.map((d) => [d.id, d]));
|
|
1902
1939
|
const fresh = inventory.definitions.filter((d) => added(d.file, d.line));
|
|
1903
|
-
if (fresh.length === 0) return [];
|
|
1904
1940
|
const freshIds = new Set(fresh.map((d) => d.id));
|
|
1905
1941
|
const ends = /* @__PURE__ */ new Map();
|
|
1906
1942
|
for (const definition of fresh) {
|
|
@@ -1921,7 +1957,8 @@ function nearDuplicates(input) {
|
|
|
1921
1957
|
if (root?.kind === "primitive" || root?.kind === "definition" && definitions.has(root.id) && !freshIds.has(root.id)) continue;
|
|
1922
1958
|
const own = inventory.looks.filter((l) => hasShape(l.shape) && inside(l, definition) && l.definition !== definition.id);
|
|
1923
1959
|
const roots = inventory.looks.filter((l) => hasShape(l.shape) && inside(l, definition) && l.definition === definition.id);
|
|
1924
|
-
|
|
1960
|
+
if (roots.length === 0 && own.length > 0) continue;
|
|
1961
|
+
const looks = roots.length > 0 ? roots : inventory.looks.filter((l) => hasShape(l.shape) && l.definition === definition.id);
|
|
1925
1962
|
let best = null;
|
|
1926
1963
|
for (const mine of looks) {
|
|
1927
1964
|
const shape = clusterShapeOf(mine);
|
|
@@ -1944,6 +1981,39 @@ function nearDuplicates(input) {
|
|
|
1944
1981
|
fix: reuse.fix
|
|
1945
1982
|
});
|
|
1946
1983
|
}
|
|
1984
|
+
const reported = fresh.filter((d) => findings.some((f) => f.file === d.file && f.line === d.line));
|
|
1985
|
+
const componentOf = (look) => look.recipe?.kind === "component" ? `${look.recipe.file}#${look.recipe.export}` : null;
|
|
1986
|
+
const uses = /* @__PURE__ */ new Map();
|
|
1987
|
+
for (const look of inventory.looks) if (look.recipe?.kind === "component" && look.file !== look.recipe.file && !look.story) uses.set(componentOf(look), (uses.get(componentOf(look)) ?? 0) + 1);
|
|
1988
|
+
const components = inventory.looks.filter((l) => hasShape(l.shape) && uses.has(componentOf(l) ?? "") && !(l.definition !== null && freshIds.has(l.definition)));
|
|
1989
|
+
const linkRoot = (look) => {
|
|
1990
|
+
const root = definitions.get(look.definition ?? "")?.root;
|
|
1991
|
+
return root?.kind === "intrinsic" ? root.tag === "a" : root?.kind === "primitive" ? /link/i.test(root.name === "default" ? root.module : root.name) : false;
|
|
1992
|
+
};
|
|
1993
|
+
for (const mine of inventory.looks) {
|
|
1994
|
+
if (mine.source !== "intrinsic" || mine.definition !== null || mine.story || !hasShape(mine.shape) || !added(mine.file, mine.line)) continue;
|
|
1995
|
+
if ([mine.shape.height, mine.shape.paddingX || null, mine.shape.radius, mine.shape.fontSize].filter((v) => v !== null).length < 3) continue;
|
|
1996
|
+
if (reported.some((d) => inside(mine, d))) continue;
|
|
1997
|
+
const shape = clusterShapeOf(mine);
|
|
1998
|
+
const mineClasses = classesOf(mine.recipe);
|
|
1999
|
+
let best = null;
|
|
2000
|
+
for (const other of components) {
|
|
2001
|
+
if (other.role !== mine.role || mine.tag === "a" !== linkRoot(other) || !compatible(shape, clusterShapeOf(other))) continue;
|
|
2002
|
+
const rank = [shapeDistance(shape, clusterShapeOf(other)), -uses.get(componentOf(other)), -overlap(mineClasses, classesOf(other.recipe))];
|
|
2003
|
+
if (!best || before(rank, best.rank)) best = { look: other, rank };
|
|
2004
|
+
}
|
|
2005
|
+
if (!best) continue;
|
|
2006
|
+
const reuse = reuseOf(best.look, definitions, importOf, mine.file);
|
|
2007
|
+
findings.push({
|
|
2008
|
+
kind: "near-duplicate",
|
|
2009
|
+
file: mine.file,
|
|
2010
|
+
line: mine.line,
|
|
2011
|
+
column: mine.column,
|
|
2012
|
+
text: `<${mine.tag}>`,
|
|
2013
|
+
message: `A hand-styled <${mine.tag}> that looks like the existing ${reuse.name} (${best.look.file}:${best.look.line}): ${describeShape(mine)}. Confirm it is the same role; if so, render ${reuse.name} instead.`,
|
|
2014
|
+
fix: reuse.fix
|
|
2015
|
+
});
|
|
2016
|
+
}
|
|
1947
2017
|
return findings.sort(byPosition);
|
|
1948
2018
|
}
|
|
1949
2019
|
function importedNames(statement) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
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));
|
|
2
2
|
import {
|
|
3
3
|
loadProject
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RQUTV7SO.js";
|
|
5
5
|
import {
|
|
6
6
|
shortHash
|
|
7
7
|
} from "./chunk-M56633DV.js";
|
|
@@ -79,11 +79,11 @@ function workflowStateDir(project, state) {
|
|
|
79
79
|
return resolve(state ?? join(homedir(), ".youi", "workflow", shortHash(`${project.repo.root}\0${project.root}`)));
|
|
80
80
|
}
|
|
81
81
|
async function ingest(link) {
|
|
82
|
-
const { readLink } = await import("./ingest-
|
|
82
|
+
const { readLink } = await import("./ingest-4C3TRSBA.js");
|
|
83
83
|
return readLink(link, { allowLocal: false });
|
|
84
84
|
}
|
|
85
85
|
async function startRuleEditor(options) {
|
|
86
|
-
const { FileStore, RuleWorkflow, serveWorkflow } = await import("./src-
|
|
86
|
+
const { FileStore, RuleWorkflow, serveWorkflow } = await import("./src-LP3MFGA4.js");
|
|
87
87
|
const projectRoot = resolve(options.project);
|
|
88
88
|
const load = { ...options.config ? { configPath: resolve(options.config) } : {}, ...options.design ? { designRoot: resolve(options.design) } : {}, ...options.root ? { productRoot: resolve(options.root) } : {} };
|
|
89
89
|
const project = await loadProject(projectRoot, load);
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
plural,
|
|
5
5
|
style,
|
|
6
6
|
workflowStateDir
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-ZXINIRJ5.js";
|
|
8
|
+
import "./chunk-RQUTV7SO.js";
|
|
9
9
|
import "./chunk-42YJX3W5.js";
|
|
10
10
|
import "./chunk-4BQPCZLL.js";
|
|
11
11
|
import "./chunk-M56633DV.js";
|
|
@@ -23,7 +23,7 @@ async function readLink(link, options) {
|
|
|
23
23
|
return { link: result.link, source: result.source, license: result.license, fetchedAt: result.fetchedAt, entries: result.entries, skipped: result.skipped, notes: result.notes };
|
|
24
24
|
}
|
|
25
25
|
async function fileIngestDraft(project, reading, state) {
|
|
26
|
-
const { FileStore, RuleWorkflow } = await import("./src-
|
|
26
|
+
const { FileStore, RuleWorkflow } = await import("./src-LP3MFGA4.js");
|
|
27
27
|
const workflow = new RuleWorkflow({ projectRoot: project.root, store: new FileStore(workflowStateDir(project, state)), ...project.configFile ? { configPath: project.configFile } : {}, ...project.designOverride ? { designRoot: project.repo.root } : {}, ...project.rootOverride ? { productRoot: project.root } : {}, ingest: async () => reading });
|
|
28
28
|
const draft = await workflow.create({ kind: "person", name: userInfo().username }, { kind: "ingest", link: reading.link });
|
|
29
29
|
return { id: draft.id, problems: draft.problems };
|
|
@@ -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-ALD2RX3X.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-RQUTV7SO.js";
|
|
34
34
|
import "./chunk-42YJX3W5.js";
|
|
35
35
|
import {
|
|
36
36
|
SHADCN_SLOTS,
|
|
@@ -64,8 +64,8 @@ import {
|
|
|
64
64
|
validateIngestContent,
|
|
65
65
|
validateLibraryContent,
|
|
66
66
|
validateStyleContent
|
|
67
|
-
} from "./chunk-
|
|
68
|
-
import "./chunk-
|
|
67
|
+
} from "./chunk-ALD2RX3X.js";
|
|
68
|
+
import "./chunk-RQUTV7SO.js";
|
|
69
69
|
import "./chunk-42YJX3W5.js";
|
|
70
70
|
import "./chunk-4BQPCZLL.js";
|
|
71
71
|
import "./chunk-M56633DV.js";
|
package/dist/hub-previews.js
CHANGED
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
selectCandidates,
|
|
18
18
|
thumbsDir,
|
|
19
19
|
writeThumbIndex
|
|
20
|
-
} from "./chunks/chunk-
|
|
21
|
-
import "./chunks/chunk-
|
|
20
|
+
} from "./chunks/chunk-O77MKELR.js";
|
|
21
|
+
import "./chunks/chunk-55I4SXOA.js";
|
|
22
22
|
import "./chunks/chunk-FVVL5JCY.js";
|
|
23
23
|
import "./chunks/chunk-M56633DV.js";
|
|
24
24
|
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-O77MKELR.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-55I4SXOA.js";
|
|
14
14
|
import "./chunks/chunk-FVVL5JCY.js";
|
|
15
15
|
import "./chunks/chunk-M56633DV.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-55I4SXOA.js";
|
|
7
7
|
import "./chunks/chunk-FVVL5JCY.js";
|
|
8
8
|
import "./chunks/chunk-WNTS7ZO4.js";
|
|
9
9
|
|
package/dist/youi.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
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-
|
|
7
|
-
import "./chunks/chunk-
|
|
5
|
+
} from "./chunks/chunk-FYG6USCG.js";
|
|
6
|
+
import "./chunks/chunk-ZXINIRJ5.js";
|
|
7
|
+
import "./chunks/chunk-RQUTV7SO.js";
|
|
8
8
|
import "./chunks/chunk-42YJX3W5.js";
|
|
9
9
|
import "./chunks/chunk-5D7PLY7A.js";
|
|
10
10
|
import "./chunks/chunk-UJMXSTUF.js";
|
package/dist/youiyoux.js
CHANGED
|
@@ -3,9 +3,9 @@ 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-
|
|
8
|
-
import "./chunks/chunk-
|
|
6
|
+
} from "./chunks/chunk-FYG6USCG.js";
|
|
7
|
+
import "./chunks/chunk-ZXINIRJ5.js";
|
|
8
|
+
import "./chunks/chunk-RQUTV7SO.js";
|
|
9
9
|
import "./chunks/chunk-42YJX3W5.js";
|
|
10
10
|
import "./chunks/chunk-5D7PLY7A.js";
|
|
11
11
|
import "./chunks/chunk-UJMXSTUF.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "youiyoux",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
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/
|
|
51
|
-
"@youiyoux/
|
|
49
|
+
"@youiyoux/cli": "0.1.21",
|
|
50
|
+
"@youiyoux/scanner": "0.1.21",
|
|
51
|
+
"@youiyoux/core": "0.1.21"
|
|
52
52
|
},
|
|
53
53
|
"exports": {
|
|
54
54
|
"./package.json": "./package.json"
|