youiyoux 0.1.7 → 0.1.8
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-O66KB7BU.js → chunk-3HON5Q5K.js} +3 -3
- package/dist/chunks/{chunk-3SQQNQDN.js → chunk-6GITMASZ.js} +1 -1
- package/dist/chunks/{chunk-N6RVMQCV.js → chunk-BARSW3JO.js} +368 -148
- package/dist/chunks/{chunk-BITS5O6H.js → chunk-DCBF7QQY.js} +4 -4
- package/dist/chunks/{chunk-YWBQO7PO.js → chunk-DWYDHVLZ.js} +74 -6
- package/dist/chunks/{chunk-SIXL67TZ.js → chunk-F33PKGES.js} +2 -2
- package/dist/chunks/{chunk-TV5UX3FE.js → chunk-FLBRX6Y3.js} +1 -1
- package/dist/chunks/{chunk-7P4UXAIY.js → chunk-HDJ2TOWZ.js} +1 -1
- package/dist/chunks/{chunk-4DVBWN7H.js → chunk-Y4IBE6WS.js} +3 -3
- package/dist/chunks/{src-SDJCFXRI.js → src-BYNWPNRT.js} +11 -1
- package/dist/chunks/{src-DYZIE4XZ.js → src-DPFJ4S2N.js} +2 -2
- package/dist/chunks/{src-4JGIPP5A.js → src-EUVBYTKY.js} +4 -4
- package/dist/chunks/{src-BKPSGYS2.js → src-M3OJMCUE.js} +3 -3
- package/dist/chunks/{src-WP66UHF7.js → src-PURAHRCR.js} +2 -2
- package/dist/chunks/{src-NWPGCDGH.js → src-YKPJ3PII.js} +6 -6
- package/dist/chunks/{src-J6GPLCVO.js → src-ZG7JU6YJ.js} +2 -2
- package/dist/hub/assets/{CandidatePanel-D6Tenu7w.js → CandidatePanel-ZzbsyZo3.js} +1 -1
- package/dist/hub/assets/{CatalogScreen-C1tvk0sB.js → CatalogScreen-DDYlvOHy.js} +1 -1
- package/dist/hub/assets/{ChangesScreen-D_6yzFGP.js → ChangesScreen-C8_EyHgJ.js} +1 -1
- package/dist/hub/assets/{CheatSheet-Ci7mG0sm.js → CheatSheet-DfcPiXdS.js} +1 -1
- package/dist/hub/assets/{CommandPalette-C4twwce1.js → CommandPalette-DfFkDTVg.js} +1 -1
- package/dist/hub/assets/DiscoverScreen-D6NTgEgk.js +2 -0
- package/dist/hub/assets/{DraftEditor-DGK0Fbp1.js → DraftEditor-CUNGYbg0.js} +1 -1
- package/dist/hub/assets/{GapsScreen-pYuuMGEF.js → GapsScreen-CqedCj4z.js} +1 -1
- package/dist/hub/assets/{HomeScreen-5rm4q3ZO.js → HomeScreen-CIj1QTkw.js} +1 -1
- package/dist/hub/assets/{InventoryScreen-CMKKrpTo.js → InventoryScreen-CyvFXa2_.js} +1 -1
- package/dist/hub/assets/{LibraryScreen-CV8lwjT6.js → LibraryScreen-C4WU0f42.js} +1 -1
- package/dist/hub/assets/{Opened-BvT3JnuG.js → Opened-CeRWkA7c.js} +1 -1
- package/dist/hub/assets/{Preview-DNOsVJ9-.js → Preview-CgW-FMB7.js} +1 -1
- package/dist/hub/assets/{RuleDetail-BNQbhncD.js → RuleDetail-BDhZ1gCd.js} +1 -1
- package/dist/hub/assets/{RulesScreen-ByYZB2Rs.js → RulesScreen-D3rSo_z2.js} +1 -1
- package/dist/hub/assets/{ScreenImage-Dypjm8_v.js → ScreenImage-DLeA3nRh.js} +1 -1
- package/dist/hub/assets/{ScreensScreen-bgwSlccW.js → ScreensScreen-bGuFIyWj.js} +1 -1
- package/dist/hub/assets/{SearchField-DyTJpGOP.js → SearchField-DtEgq9-Q.js} +1 -1
- package/dist/hub/assets/{ServiceDown-f9NYtkr_.js → ServiceDown-Bn6AcA3J.js} +1 -1
- package/dist/hub/assets/{SpecimenCapture-DFoGMhOM.js → SpecimenCapture-p6YErF5y.js} +1 -1
- package/dist/hub/assets/{Specimens-BGwJj05V.js → Specimens-DuaE0WeO.js} +2 -2
- package/dist/hub/assets/{StackScreen-q132_QG3.js → StackScreen-DHDulDng.js} +1 -1
- package/dist/hub/assets/{StubScreens-DWhYvJku.js → StubScreens-CmhVNX_Z.js} +1 -1
- package/dist/hub/assets/{StyleScreen-CcgUv16e.js → StyleScreen-LwTqfGID.js} +1 -1
- package/dist/hub/assets/{Tabs-Dy1Z02s7.js → Tabs-Cbh9BCKW.js} +1 -1
- package/dist/hub/assets/{TokenDetail-DsYgNrPw.js → TokenDetail-BICobLK1.js} +1 -1
- package/dist/hub/assets/{TokensScreen-CTT0GbAH.js → TokensScreen-CyTHn55q.js} +1 -1
- package/dist/hub/assets/WorkspaceScreen-uPWqfklh.js +1 -0
- package/dist/hub/assets/{client-CIo9EOzr.js → client-BXHiuV_w.js} +1 -1
- package/dist/hub/assets/{discover-DGlqvyIe.js → discover-CFhyKler.js} +1 -1
- package/dist/hub/assets/{dist-2euSoh6x.js → dist-C6iTWL0b.js} +1 -1
- package/dist/hub/assets/{dist-CpzxT6kj.js → dist-DYNYuTjI.js} +1 -1
- package/dist/hub/assets/{dist-D8LFTd5W.js → dist-VmEpVQjP.js} +1 -1
- package/dist/hub/assets/{family-tiles-Cc7tTwyr.js → family-tiles-B8_onXUi.js} +1 -1
- package/dist/hub/assets/folder-tree-YghfTmlZ.js +1 -0
- package/dist/hub/assets/main-CfbpuT4Y.js +2 -0
- package/dist/hub/assets/{try-live-C-dwP1zF.js → try-live-CX04d2L2.js} +1 -1
- package/dist/hub/assets/workflow-DbBdiOmA.js +1 -0
- package/dist/hub/index.html +2 -1
- package/dist/hub-previews.js +5 -5
- package/dist/hub-server.js +3 -3
- package/dist/hub-snapshot.js +3 -2
- package/dist/schema/youi.status.schema.json +306 -0
- package/dist/schema/youi.workspace.schema.json +31 -0
- package/dist/youi.js +6 -6
- package/dist/youiyoux.js +6 -6
- package/package.json +4 -4
- package/dist/hub/assets/DiscoverScreen-SOJMVxIq.js +0 -2
- package/dist/hub/assets/main-Bjq_U0cU.js +0 -2
- package/dist/hub/assets/workflow-CnSY-W41.js +0 -1
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
vendoredPath,
|
|
54
54
|
whereUsed,
|
|
55
55
|
withFile
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-3HON5Q5K.js";
|
|
57
57
|
import {
|
|
58
58
|
escapingLinks,
|
|
59
59
|
within
|
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
libraryOfPackage,
|
|
68
68
|
packageOf,
|
|
69
69
|
playwrightCli
|
|
70
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-HDJ2TOWZ.js";
|
|
71
71
|
import {
|
|
72
72
|
MissingIndexError,
|
|
73
73
|
buildGaps,
|
|
@@ -91,7 +91,7 @@ import {
|
|
|
91
91
|
showFromCatalog,
|
|
92
92
|
storeLocation,
|
|
93
93
|
syncIndex
|
|
94
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-6GITMASZ.js";
|
|
95
95
|
import {
|
|
96
96
|
DL_EXT,
|
|
97
97
|
buildTokens,
|
|
@@ -101,7 +101,7 @@ import {
|
|
|
101
101
|
parseCssColor,
|
|
102
102
|
parseDimension,
|
|
103
103
|
readRules
|
|
104
|
-
} from "./chunk-
|
|
104
|
+
} from "./chunk-FLBRX6Y3.js";
|
|
105
105
|
import {
|
|
106
106
|
Baseline,
|
|
107
107
|
DESIGN_CONFIG_FILE,
|
|
@@ -115,6 +115,8 @@ import {
|
|
|
115
115
|
PACKAGE_NAME,
|
|
116
116
|
ProjectConfig,
|
|
117
117
|
ScanReport,
|
|
118
|
+
WORKSPACE_FILE,
|
|
119
|
+
WorkspaceConfig,
|
|
118
120
|
copyleft,
|
|
119
121
|
executionLabel,
|
|
120
122
|
findFiles,
|
|
@@ -136,7 +138,7 @@ import {
|
|
|
136
138
|
shortHash,
|
|
137
139
|
toPosix,
|
|
138
140
|
writeFileAtomic
|
|
139
|
-
} from "./chunk-
|
|
141
|
+
} from "./chunk-DWYDHVLZ.js";
|
|
140
142
|
import {
|
|
141
143
|
__toESM
|
|
142
144
|
} from "./chunk-WNTS7ZO4.js";
|
|
@@ -146,7 +148,7 @@ var import_yaml4 = __toESM(require_dist(), 1);
|
|
|
146
148
|
import { execFile as execFile5 } from "node:child_process";
|
|
147
149
|
import { existsSync as existsSync5 } from "node:fs";
|
|
148
150
|
import { appendFile as appendFile2, readFile as readFile10, rm as rm6, rmdir as rmdir3 } from "node:fs/promises";
|
|
149
|
-
import { basename as basename5, dirname as
|
|
151
|
+
import { basename as basename5, dirname as dirname13, join as join25, relative as relative11, resolve as resolve15 } from "node:path";
|
|
150
152
|
import { parseArgs, promisify as promisify5 } from "node:util";
|
|
151
153
|
|
|
152
154
|
// ../cli/src/check.ts
|
|
@@ -164,7 +166,7 @@ import { join as join2, relative, resolve } from "node:path";
|
|
|
164
166
|
|
|
165
167
|
// ../cli/src/command.ts
|
|
166
168
|
var COMMAND = "youiyoux";
|
|
167
|
-
var SUBCOMMANDS = ["show", "where", "bom", "check", "baseline", "rules", "plan", "migrate", "init", "adopt", "system", "sync", "link", "unlink", "scan", "watch", "hooks", "agents", "mcp", "ui", "library", "discover", "index", "report", "render", "screens", "requests", "detect", "build", "parity", "schema", "inventory", "gaps", "help"];
|
|
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"];
|
|
168
170
|
|
|
169
171
|
// ../cli/src/agents.ts
|
|
170
172
|
var import_yaml = __toESM(require_dist(), 1);
|
|
@@ -1058,7 +1060,7 @@ async function runCheck(project2, options = {}) {
|
|
|
1058
1060
|
const { report } = scan;
|
|
1059
1061
|
const checked = new Set(scan.files);
|
|
1060
1062
|
const unmatched = scope ? [...scope].filter((f) => !checked.has(f)) : [];
|
|
1061
|
-
const
|
|
1063
|
+
const failed2 = report.coverage.failed.filter((f) => !scope || scope.has(f.file) || !/\.(tsx?|css)$/.test(f.file));
|
|
1062
1064
|
const wantedRule = (id) => !options.rule || id.endsWith(`/rule/${options.rule}`);
|
|
1063
1065
|
const violations = report.violations.filter((v) => wantedRule(v.rule) && (!options.quiet || v.severity === "error"));
|
|
1064
1066
|
const notRun = failedChecks(report.checks).filter((c) => wantedRule(c.rule));
|
|
@@ -1069,7 +1071,7 @@ async function runCheck(project2, options = {}) {
|
|
|
1069
1071
|
const failing = baseline ? [...baseline.comparison.new, ...baseline.comparison.regressed] : violations;
|
|
1070
1072
|
const errors = failing.filter((v) => v.severity === "error").length + (lock ?? []).filter((i) => i.severity === "error").length;
|
|
1071
1073
|
const drift = diff ? await analyseChange(project2, scan, diff, { violations }) : null;
|
|
1072
|
-
return { identity: scan.identity, scan, scope, unmatched, failed, notRun, violations, lock, baseline, errors, incomplete: unmatched.length > 0 ||
|
|
1074
|
+
return { identity: scan.identity, scan, scope, unmatched, failed: failed2, notRun, violations, lock, baseline, errors, incomplete: unmatched.length > 0 || failed2.length > 0 || notRun.length > 0 || (drift?.incomplete.length ?? 0) > 0, diff: drift };
|
|
1073
1075
|
}
|
|
1074
1076
|
async function lockIssues(project2) {
|
|
1075
1077
|
const lock = await verifyLock(project2);
|
|
@@ -1779,18 +1781,18 @@ async function runClaudeHook(input, target = {}) {
|
|
|
1779
1781
|
try {
|
|
1780
1782
|
const project2 = await load(target, dirname5(file));
|
|
1781
1783
|
const real = (path) => realpath3(path).catch(() => path);
|
|
1782
|
-
const
|
|
1783
|
-
if (!isChecked(project2,
|
|
1784
|
-
const found = await changeFor(() => workingTreeChange(project2, void 0, [
|
|
1784
|
+
const relative12 = relPath(await real(project2.root), await real(file));
|
|
1785
|
+
if (!isChecked(project2, relative12)) return SILENT;
|
|
1786
|
+
const found = await changeFor(() => workingTreeChange(project2, void 0, [relative12]));
|
|
1785
1787
|
if (found.problem !== void 0) return claudeContext(found.problem, project2.root);
|
|
1786
1788
|
const { change } = found;
|
|
1787
1789
|
const result = configured(project2) ? await runCheck(project2, { files: [file], lock: false, baseline: await baselineFor(project2, target), diff: change }) : await runRepoCheck(project2, change);
|
|
1788
1790
|
const lines = findingLines(result, project2.root);
|
|
1789
|
-
const see = COMPONENT_FILE.test(
|
|
1790
|
-
if (lines.length === 0) return see ? claudeContext(`youiyoux: ${
|
|
1791
|
+
const see = COMPONENT_FILE.test(relative12) ? `See it: youiyoux render ${quoted(relative12)} (or the MCP tool ui_render), then open the images: light and dark, desktop and phone, accessibility issues and the diff against the base.` : null;
|
|
1792
|
+
if (lines.length === 0) return see ? claudeContext(`youiyoux: ${relative12} passes the design-system check. ${see}`, project2.root) : SILENT;
|
|
1791
1793
|
const older = "violations" in result ? result.violations.filter((v) => !isAdded(change.added, v.file, v.line)).length : 0;
|
|
1792
1794
|
const known = older > 0 ? ` (${older} older findings on unchanged lines omitted)` : "";
|
|
1793
|
-
return claudeContext(`youiyoux design-system check (advisory) on ${
|
|
1795
|
+
return claudeContext(`youiyoux design-system check (advisory) on ${relative12}${known}:
|
|
1794
1796
|
${lines.join("\n")}${!configured(project2) ? `
|
|
1795
1797
|
${result.diff?.notes.join("\n")}` : ""}
|
|
1796
1798
|
Fix these before finishing (each "Fix:" says what to write); \`youiyoux show <component>\` and the youiyoux MCP tools give the legal values. CI runs the authoritative check.${see ? `
|
|
@@ -2085,7 +2087,7 @@ import { homedir, userInfo } from "node:os";
|
|
|
2085
2087
|
import { join as join12, resolve as resolve6 } from "node:path";
|
|
2086
2088
|
async function swapImpact(candidate, family) {
|
|
2087
2089
|
try {
|
|
2088
|
-
const { discoverIndexPath: discoverIndexPath2, sharedStore: sharedStore2 } = await import("./src-
|
|
2090
|
+
const { discoverIndexPath: discoverIndexPath2, sharedStore: sharedStore2 } = await import("./src-DPFJ4S2N.js");
|
|
2089
2091
|
const path = discoverIndexPath2();
|
|
2090
2092
|
if (!process.env.DATABASE_URL && !existsSync(path)) return null;
|
|
2091
2093
|
const impact = await (await sharedStore2(path, process.env, { readOnly: true })).swapImpact(candidate, family);
|
|
@@ -2096,7 +2098,7 @@ async function swapImpact(candidate, family) {
|
|
|
2096
2098
|
}
|
|
2097
2099
|
async function libraryLicence(id) {
|
|
2098
2100
|
try {
|
|
2099
|
-
const { discoverCacheDir: discoverCacheDir2, findListing } = await import("./src-
|
|
2101
|
+
const { discoverCacheDir: discoverCacheDir2, findListing } = await import("./src-DPFJ4S2N.js");
|
|
2100
2102
|
const { entry } = await findListing(discoverCacheDir2(void 0, process.env), id);
|
|
2101
2103
|
return entry.id === id ? entry.license : null;
|
|
2102
2104
|
} catch {
|
|
@@ -2104,7 +2106,7 @@ async function libraryLicence(id) {
|
|
|
2104
2106
|
}
|
|
2105
2107
|
}
|
|
2106
2108
|
async function startRuleEditor(options) {
|
|
2107
|
-
const { FileStore, RuleWorkflow, serveWorkflow } = await import("./src-
|
|
2109
|
+
const { FileStore, RuleWorkflow, serveWorkflow } = await import("./src-EUVBYTKY.js");
|
|
2108
2110
|
const projectRoot = resolve6(options.project);
|
|
2109
2111
|
const load2 = { ...options.config ? { configPath: resolve6(options.config) } : {}, ...options.design ? { designRoot: resolve6(options.design) } : {}, ...options.root ? { productRoot: resolve6(options.root) } : {} };
|
|
2110
2112
|
const project2 = await loadProject(projectRoot, load2);
|
|
@@ -2145,7 +2147,7 @@ function builtHubPlan(toolRoot, options, out) {
|
|
|
2145
2147
|
if (options.watch && !namesSystem(options)) throw new Error("--watch keeps a system's snapshot live: name it with --design or --project (the demo system is not watched)");
|
|
2146
2148
|
const hub = join13(toolRoot, BUILT_HUB);
|
|
2147
2149
|
const snapshot = flags.length > 0 ? [join13(toolRoot, "hub-snapshot.js"), "--out", out, ...flags] : null;
|
|
2148
|
-
const server = [join13(toolRoot, "hub-server.js"), "--dist", hub, "--kit", join13(hub, "kit"), "--snapshot", snapshot ? out : join13(toolRoot, BUILT_DEMO), ...snapshot ? ["--build-frame"] : [], ...options.port ? ["--port", options.port] : [], ...options.api ? ["--api", options.api] : [], ...options.watch ? ["--live"] : []];
|
|
2150
|
+
const server = [join13(toolRoot, "hub-server.js"), "--dist", hub, "--kit", join13(hub, "kit"), "--snapshot", snapshot ? out : join13(toolRoot, BUILT_DEMO), ...snapshot ? ["--build-frame"] : [], ...options.port ? ["--port", options.port] : [], ...options.api ? ["--api", options.api] : [], ...options.watch || options.workspace ? ["--live"] : []];
|
|
2149
2151
|
return { snapshot, server, watch: options.watch && snapshot ? [...snapshot, "--watch"] : null };
|
|
2150
2152
|
}
|
|
2151
2153
|
function run5(args, cwd, env, started) {
|
|
@@ -2170,6 +2172,7 @@ async function runBuiltHub(toolRoot, options) {
|
|
|
2170
2172
|
const code = await run5(plan.snapshot, process.cwd(), {}, (child) => children.add(child));
|
|
2171
2173
|
if (code !== 0) return code;
|
|
2172
2174
|
}
|
|
2175
|
+
options.workspace?.((project2) => run5(builtHubPlan(toolRoot, { ...options, project: project2 }, out).snapshot, process.cwd(), {}, (child) => children.add(child)));
|
|
2173
2176
|
if (plan.watch) children.add(spawn(process.execPath, plan.watch, { cwd: process.cwd(), stdio: "inherit" }));
|
|
2174
2177
|
return await run5(plan.server, process.cwd(), {}, (child) => children.add(child));
|
|
2175
2178
|
} finally {
|
|
@@ -2189,6 +2192,7 @@ async function runHub(toolRoot, options) {
|
|
|
2189
2192
|
const code = await run5(plan.snapshot, process.cwd(), {});
|
|
2190
2193
|
if (code !== 0) return code;
|
|
2191
2194
|
}
|
|
2195
|
+
options.workspace?.((project2) => run5(hubPlan(toolRoot, { ...options, project: project2 }).snapshot, process.cwd(), {}));
|
|
2192
2196
|
const watcher = plan.watch ? spawn(process.execPath, plan.watch, { cwd: process.cwd(), stdio: "inherit" }) : null;
|
|
2193
2197
|
try {
|
|
2194
2198
|
return await run5(plan.vite, plan.web, plan.env);
|
|
@@ -2630,15 +2634,193 @@ async function extractSystem(project2, dir, options = {}) {
|
|
|
2630
2634
|
}
|
|
2631
2635
|
}
|
|
2632
2636
|
|
|
2637
|
+
// ../cli/src/status.ts
|
|
2638
|
+
import { realpath as realpath5 } from "node:fs/promises";
|
|
2639
|
+
import { dirname as dirname9, join as join16, relative as relative8, resolve as resolve10 } from "node:path";
|
|
2640
|
+
var placeOf = (cwd, root) => {
|
|
2641
|
+
const rel = relative8(cwd, root) || ".";
|
|
2642
|
+
return rel.split(/[\\/]/).filter((part) => part === "..").length > 1 ? resolve10(root) : rel;
|
|
2643
|
+
};
|
|
2644
|
+
var WRITES = /* @__PURE__ */ new Set(["created", "updated", "merged", "adopted", "conflict", "removed"]);
|
|
2645
|
+
function sourceOf(project2) {
|
|
2646
|
+
if (project2.linked) return `your checkout ${project2.linked}`;
|
|
2647
|
+
const source = project2.config.source;
|
|
2648
|
+
if ("package" in source) return `package ${source.package}`;
|
|
2649
|
+
if ("git" in source) return `git ${source.git} at ${source.ref}`;
|
|
2650
|
+
return resolve10(project2.root) === resolve10(project2.repo.root) ? "this repo" : `path ${source.path}`;
|
|
2651
|
+
}
|
|
2652
|
+
function nextStep(s) {
|
|
2653
|
+
if (s.sync.state === "never") return "youiyoux sync: this product has never been synced with its System";
|
|
2654
|
+
if (s.sync.state === "conflict") return "youiyoux sync: resolve the conflicts it reports, then youiyoux sync --adopt records them";
|
|
2655
|
+
if (s.sync.state === "behind") return `youiyoux sync: ${plural(s.sync.changes.length, "file")} would change`;
|
|
2656
|
+
if (s.check.incomplete) return "youiyoux check: some files or rules could not be checked, and it says which";
|
|
2657
|
+
if (s.check.errors > 0) return `youiyoux check: fix ${plural(s.check.errors, "error")}`;
|
|
2658
|
+
if (s.requests.open > 0) return `youiyoux requests: answer ${plural(s.requests.open, "open request")}`;
|
|
2659
|
+
if (s.check.warnings > 0 && !s.check.baseline) return `youiyoux check: ${plural(s.check.warnings, "warning")} to fix, or youiyoux baseline records them as accepted debt`;
|
|
2660
|
+
return "nothing to do";
|
|
2661
|
+
}
|
|
2662
|
+
async function projectStatus(project2, cwd = process.cwd()) {
|
|
2663
|
+
const lock = await readLock(project2.root);
|
|
2664
|
+
const { actions } = await syncProject(project2, { dryRun: true });
|
|
2665
|
+
const changes = actions.filter((a) => WRITES.has(a.action)).map((a) => ({ file: a.file, action: a.action }));
|
|
2666
|
+
const baselineFile2 = baselinePath(project2);
|
|
2667
|
+
const check = await runCheck(project2, { baseline: await readTextOrNull(baselineFile2) === null ? null : baselineFile2 });
|
|
2668
|
+
const comparison = check.baseline?.comparison;
|
|
2669
|
+
const counted = comparison ? [...comparison.new, ...comparison.regressed] : check.violations;
|
|
2670
|
+
const usages = check.scan.report.usages;
|
|
2671
|
+
const { RequestStore } = await import("./src-EUVBYTKY.js");
|
|
2672
|
+
const requests = await new RequestStore(project2.root, project2.config.id).list();
|
|
2673
|
+
const status = {
|
|
2674
|
+
id: project2.config.id,
|
|
2675
|
+
root: placeOf(cwd, project2.root),
|
|
2676
|
+
system: { id: project2.system.config.id, name: project2.system.config.name, version: project2.system.config.version, source: sourceOf(project2), linked: Boolean(project2.linked), commit: project2.designCommit ?? null },
|
|
2677
|
+
lock: lock ? { systemVersion: lock.systemVersion, syncedAt: lock.syncedAt } : null,
|
|
2678
|
+
sync: { state: lock === null ? "never" : actions.some((a) => a.action === "conflict") ? "conflict" : changes.length > 0 ? "behind" : "current", changes },
|
|
2679
|
+
drift: (await verifyLock(project2) ?? []).map((i) => ({ file: i.file, severity: i.severity, message: i.message })),
|
|
2680
|
+
check: {
|
|
2681
|
+
errors: check.errors,
|
|
2682
|
+
warnings: counted.filter((v) => v.severity === "warn").length,
|
|
2683
|
+
baseline: comparison ? { known: comparison.known.length, new: comparison.new.length + comparison.regressed.length, fixed: comparison.fixed.reduce((n, f) => n + f.gone, 0) } : null,
|
|
2684
|
+
incomplete: check.incomplete
|
|
2685
|
+
},
|
|
2686
|
+
components: { system: project2.system.components.length, used: new Set(usages.map((u) => u.element)).size, sites: usages.length },
|
|
2687
|
+
requests: { open: requests.requests.filter((r) => r.status === "open").length, addressed: requests.requests.filter((r) => r.status === "addressed").length, unreadable: requests.unreadable.length }
|
|
2688
|
+
};
|
|
2689
|
+
return { ...status, next: nextStep(status) };
|
|
2690
|
+
}
|
|
2691
|
+
async function statusTargets(cwd, named2) {
|
|
2692
|
+
if (named2) return { roots: [resolve10(named2)], workspace: null };
|
|
2693
|
+
const product2 = findUp(cwd, PROJECT_FILE);
|
|
2694
|
+
if (product2) return { roots: [product2], workspace: null };
|
|
2695
|
+
const at = findUp(cwd, WORKSPACE_FILE);
|
|
2696
|
+
if (at) {
|
|
2697
|
+
const file = join16(at, WORKSPACE_FILE);
|
|
2698
|
+
const workspace = await readDefinition(file, WorkspaceConfig);
|
|
2699
|
+
return { roots: workspace.projects.map((p) => resolve10(at, p)), workspace: file };
|
|
2700
|
+
}
|
|
2701
|
+
const top = findUp(cwd, ".git") ?? null;
|
|
2702
|
+
if (top === null) return { roots: [], workspace: null };
|
|
2703
|
+
const configs = await findFiles(cwd, [`**/${PROJECT_FILE}`]);
|
|
2704
|
+
const roots = [];
|
|
2705
|
+
for (const config of configs) {
|
|
2706
|
+
const dir = resolve10(cwd, dirname9(config));
|
|
2707
|
+
if (await realpath5(findUp(dir, ".git") ?? dir) === await realpath5(top)) roots.push(dir);
|
|
2708
|
+
}
|
|
2709
|
+
return { roots, workspace: null };
|
|
2710
|
+
}
|
|
2711
|
+
async function workspaceStatus(cwd, named2) {
|
|
2712
|
+
const { roots, workspace } = await statusTargets(cwd, named2);
|
|
2713
|
+
const projects = [];
|
|
2714
|
+
for (const root of roots) {
|
|
2715
|
+
try {
|
|
2716
|
+
projects.push(await projectStatus(await loadProject(root), cwd));
|
|
2717
|
+
} catch (error) {
|
|
2718
|
+
const label = placeOf(cwd, root);
|
|
2719
|
+
projects.push({ root: label, error: error instanceof Error ? error.message : String(error), next: await readTextOrNull(join16(root, PROJECT_FILE)) === null ? `youiyoux adopt or youiyoux init --design <dir> in ${label}` : `fix ${join16(label, PROJECT_FILE)}` });
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
return { schema: "youi.status/v1", generatedAt: (/* @__PURE__ */ new Date()).toISOString(), workspace: workspace ? relative8(cwd, workspace) || WORKSPACE_FILE : null, projects };
|
|
2723
|
+
}
|
|
2724
|
+
var failed = (p) => "error" in p;
|
|
2725
|
+
function projectLines(s) {
|
|
2726
|
+
const row = (label, text) => ` ${padEnd(label, 11)} ${text}`;
|
|
2727
|
+
const synced = s.lock ? `synced ${s.lock.syncedAt.slice(0, 10)}${s.lock.systemVersion !== s.system.version ? ` at v${s.lock.systemVersion}` : ""}` : "never synced";
|
|
2728
|
+
const sync = { current: style.ok("up to date"), behind: style.warn(`behind: ${plural(s.sync.changes.length, "file")} would change`), conflict: style.error(`conflict: ${plural(s.sync.changes.filter((c) => c.action === "conflict").length, "file")}`), never: style.warn("never synced") }[s.sync.state];
|
|
2729
|
+
const edited = s.drift.filter((d) => d.severity === "warn");
|
|
2730
|
+
const broken = s.drift.filter((d) => d.severity === "error");
|
|
2731
|
+
const drift = s.drift.length === 0 ? style.ok("none") : [broken.length > 0 ? style.error(`${plural(broken.length, "file")} wrong (${broken.slice(0, 3).map((d) => d.file.split("/").at(-1)).join(", ")})`) : "", edited.length > 0 ? style.warn(`${plural(edited.length, "owned file")} edited locally, merged on sync (${edited.slice(0, 3).map((d) => d.file.split("/").at(-1)).join(", ")})`) : ""].filter(Boolean).join("; ");
|
|
2732
|
+
const { check } = s;
|
|
2733
|
+
const counts = `${check.errors > 0 ? style.error(plural(check.errors, "error")) : style.ok("0 errors")} \xB7 ${plural(check.warnings, "warning")}`;
|
|
2734
|
+
const baseline = check.baseline ? style.dim(` beyond the baseline (${check.baseline.known} accepted${check.baseline.fixed > 0 ? `, ${check.baseline.fixed} fixed` : ""})`) : "";
|
|
2735
|
+
return [
|
|
2736
|
+
`${style.bold(s.id)}${s.root === s.id ? "" : ` ${style.dim(`\xB7 ${s.root}`)}`} \xB7 ${s.system.name} v${s.system.version} ${style.dim(`(${s.system.source}${s.system.linked ? ", linked" : ""}) \xB7 ${synced}`)}`,
|
|
2737
|
+
row("sync", sync),
|
|
2738
|
+
row("drift", drift),
|
|
2739
|
+
row("check", `${counts}${baseline}${check.incomplete ? style.warn(" \xB7 incomplete: not a pass") : ""}`),
|
|
2740
|
+
row("components", `${s.components.used} of ${s.components.system} System components used, at ${plural(s.components.sites, "site")}`),
|
|
2741
|
+
row("requests", s.requests.open + s.requests.addressed + s.requests.unreadable === 0 ? style.dim("none") : [s.requests.open > 0 ? style.warn(`${s.requests.open} open`) : "0 open", `${s.requests.addressed} addressed`, ...s.requests.unreadable > 0 ? [style.error(`${s.requests.unreadable} unreadable`)] : []].join(" \xB7 ")),
|
|
2742
|
+
`${style.bold("Next:")} ${s.next}`
|
|
2743
|
+
];
|
|
2744
|
+
}
|
|
2745
|
+
function renderStatus(report) {
|
|
2746
|
+
if (report.projects.length === 0) return `${style.warn("!")} no product here: no ${PROJECT_FILE} upward, no ${WORKSPACE_FILE}, and none in this repository below here
|
|
2747
|
+
Next: youiyoux adopt makes this product's own UI its design system, or youiyoux init --design <dir> follows one`;
|
|
2748
|
+
const blocks = report.projects.map((p) => failed(p) ? [`${style.bold(p.root)} ${style.error("\u2716")} ${p.error}`, `${style.bold("Next:")} ${p.next}`] : projectLines(p));
|
|
2749
|
+
const head = report.projects.length > 1 ? [`${style.bold("workspace")} ${style.dim(`\xB7 ${plural(report.projects.length, "product")}${report.workspace ? ` from ${report.workspace}` : " in this repository"}`)}`, ""] : [];
|
|
2750
|
+
return [...head, ...blocks.flatMap((b, i) => i === 0 ? b : ["", ...b])].join("\n");
|
|
2751
|
+
}
|
|
2752
|
+
var statusExitCode = (report) => report.projects.some((p) => failed(p) || p.check.incomplete || p.check.errors > 0 || p.sync.state === "conflict") ? 1 : 0;
|
|
2753
|
+
|
|
2754
|
+
// ../cli/src/workspace-hub.ts
|
|
2755
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
2756
|
+
import { createServer } from "node:http";
|
|
2757
|
+
var KEY_HEADER = "x-youi-session";
|
|
2758
|
+
function send(res, status, body) {
|
|
2759
|
+
res.writeHead(status, { "Content-Type": "application/json", "Cache-Control": "no-store" });
|
|
2760
|
+
res.end(JSON.stringify(body));
|
|
2761
|
+
}
|
|
2762
|
+
async function readBody(req) {
|
|
2763
|
+
let text = "";
|
|
2764
|
+
for await (const chunk2 of req) {
|
|
2765
|
+
text += String(chunk2);
|
|
2766
|
+
if (text.length > 4096) throw new Error("request too large");
|
|
2767
|
+
}
|
|
2768
|
+
return text ? JSON.parse(text) : {};
|
|
2769
|
+
}
|
|
2770
|
+
async function startWorkspaceHub(options) {
|
|
2771
|
+
const key2 = randomBytes2(18).toString("base64url");
|
|
2772
|
+
let report = await options.status();
|
|
2773
|
+
let current = options.current;
|
|
2774
|
+
let busy = false;
|
|
2775
|
+
const server = createServer((req, res) => {
|
|
2776
|
+
void (async () => {
|
|
2777
|
+
const path = (req.url ?? "").split("?")[0];
|
|
2778
|
+
if (req.method === "GET" && path === "/api/workspace") return send(res, 200, { report, current });
|
|
2779
|
+
if (req.method !== "POST" || path !== "/api/workspace/open" && path !== "/api/workspace/refresh") {
|
|
2780
|
+
return send(res, 404, { error: "Not in a workspace hub: Rules and Changes are read-only here; youiyoux ui --project <dir> opens the rule editor on one product" });
|
|
2781
|
+
}
|
|
2782
|
+
if (req.headers[KEY_HEADER] !== key2) return send(res, 401, { error: "this tab does not carry this run's key" });
|
|
2783
|
+
if (busy) return send(res, 409, { error: "another product is opening; try again in a moment" });
|
|
2784
|
+
busy = true;
|
|
2785
|
+
try {
|
|
2786
|
+
if (path === "/api/workspace/refresh") {
|
|
2787
|
+
report = await options.status();
|
|
2788
|
+
return send(res, 200, { report, current });
|
|
2789
|
+
}
|
|
2790
|
+
const { index } = await readBody(req);
|
|
2791
|
+
const entry = typeof index === "number" && Number.isInteger(index) ? report.projects[index] : void 0;
|
|
2792
|
+
if (entry === void 0 || options.roots[index] === void 0) return send(res, 400, { error: `no product ${JSON.stringify(index)} in this workspace` });
|
|
2793
|
+
if ("error" in entry) return send(res, 400, { error: `${entry.root} cannot be opened: ${entry.error}`, problems: [entry.next] });
|
|
2794
|
+
const code = await options.open(options.roots[index]);
|
|
2795
|
+
if (code !== 0) return send(res, 500, { error: `the snapshot of ${entry.root} failed (exit ${code}); the hub still shows the product it showed` });
|
|
2796
|
+
current = index;
|
|
2797
|
+
return send(res, 200, { report, current });
|
|
2798
|
+
} catch (error) {
|
|
2799
|
+
return send(res, 400, { error: error instanceof Error ? error.message : String(error) });
|
|
2800
|
+
} finally {
|
|
2801
|
+
busy = false;
|
|
2802
|
+
}
|
|
2803
|
+
})();
|
|
2804
|
+
});
|
|
2805
|
+
await new Promise((done) => server.listen(0, "127.0.0.1", done));
|
|
2806
|
+
const address = server.address();
|
|
2807
|
+
const port = typeof address === "object" && address ? address.port : 0;
|
|
2808
|
+
return {
|
|
2809
|
+
url: `http://127.0.0.1:${port}`,
|
|
2810
|
+
key: key2,
|
|
2811
|
+
close: () => new Promise((done) => server.close(() => done()))
|
|
2812
|
+
};
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2633
2815
|
// ../cli/src/index-store.ts
|
|
2634
2816
|
import { appendFile, mkdir as mkdir4, readFile as readFile6, stat as stat2, rename as rename2, mkdtemp as mkdtemp4, rm as rm5 } from "node:fs/promises";
|
|
2635
|
-
import { dirname as
|
|
2817
|
+
import { dirname as dirname10, join as join17, resolve as resolve11 } from "node:path";
|
|
2636
2818
|
var SOURCES_FILE = "index-sources.json";
|
|
2637
2819
|
var SCANS_LOG = "scans.jsonl";
|
|
2638
2820
|
var EMPTY = { discover: null, inventories: [], projects: [] };
|
|
2639
2821
|
async function readIndexSources(home) {
|
|
2640
2822
|
try {
|
|
2641
|
-
const raw = JSON.parse(await readFile6(
|
|
2823
|
+
const raw = JSON.parse(await readFile6(join17(home, SOURCES_FILE), "utf8"));
|
|
2642
2824
|
return { discover: raw.discover ?? null, inventories: raw.inventories ?? [], projects: raw.projects ?? [] };
|
|
2643
2825
|
} catch {
|
|
2644
2826
|
return EMPTY;
|
|
@@ -2651,14 +2833,14 @@ async function noteSource(home, change) {
|
|
|
2651
2833
|
inventories: change.inventory && !sources.inventories.includes(change.inventory) ? [...sources.inventories, change.inventory] : sources.inventories,
|
|
2652
2834
|
projects: change.project ? [...sources.projects.filter((p) => p.root !== change.project.root), change.project] : sources.projects
|
|
2653
2835
|
};
|
|
2654
|
-
await writeFileAtomic(
|
|
2836
|
+
await writeFileAtomic(join17(home, SOURCES_FILE), `${JSON.stringify(next2, null, 2)}
|
|
2655
2837
|
`);
|
|
2656
2838
|
}
|
|
2657
2839
|
async function recordInventory(store, home, report, file) {
|
|
2658
|
-
const run7 = inventoryRun(report,
|
|
2840
|
+
const run7 = inventoryRun(report, resolve11(file));
|
|
2659
2841
|
const logged = { run: run7.run, source: run7.source, scannedAt: run7.scannedAt, projects: run7.projects, families: run7.families };
|
|
2660
2842
|
await mkdir4(home, { recursive: true });
|
|
2661
|
-
await appendFile(
|
|
2843
|
+
await appendFile(join17(home, SCANS_LOG), `${JSON.stringify({ schema: "youi.scan-log/v1", ...logged })}
|
|
2662
2844
|
`);
|
|
2663
2845
|
await store.recordInventory(run7);
|
|
2664
2846
|
await noteSource(home, { inventory: run7.source });
|
|
@@ -2669,7 +2851,7 @@ async function recordProject(store, project2, usage) {
|
|
|
2669
2851
|
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 }));
|
|
2670
2852
|
}
|
|
2671
2853
|
async function readLog(home) {
|
|
2672
|
-
const text = await readFile6(
|
|
2854
|
+
const text = await readFile6(join17(home, SCANS_LOG), "utf8").catch(() => "");
|
|
2673
2855
|
return text.split("\n").flatMap((line) => {
|
|
2674
2856
|
if (!line.trim()) return [];
|
|
2675
2857
|
try {
|
|
@@ -2684,9 +2866,9 @@ async function rebuildIndex(path, options = {}) {
|
|
|
2684
2866
|
const started = performance.now();
|
|
2685
2867
|
const env = options.env ?? process.env;
|
|
2686
2868
|
const home = indexHome(path, env);
|
|
2687
|
-
await mkdir4(
|
|
2869
|
+
await mkdir4(dirname10(path), { recursive: true });
|
|
2688
2870
|
const scratch = !env.DATABASE_URL ? await mkdtemp4(`${path}.rebuild-`) : null;
|
|
2689
|
-
const target = scratch ?
|
|
2871
|
+
const target = scratch ? join17(scratch, "index.db") : path;
|
|
2690
2872
|
const store = scratch ? await openSqlite(target) : await sharedStore(path, env);
|
|
2691
2873
|
try {
|
|
2692
2874
|
if (env.DATABASE_URL) await store.reset();
|
|
@@ -2694,7 +2876,7 @@ async function rebuildIndex(path, options = {}) {
|
|
|
2694
2876
|
const sources = await readIndexSources(home);
|
|
2695
2877
|
const cache = options.discoverCache ?? sources.discover;
|
|
2696
2878
|
let discover = { cache, chosen: 0, all: 0 };
|
|
2697
|
-
if (cache && await stat2(
|
|
2879
|
+
if (cache && await stat2(join17(cache, "index.json")).then(() => true, () => false)) {
|
|
2698
2880
|
const loaded = await ingestCatalog(store, cache);
|
|
2699
2881
|
discover = { cache, chosen: loaded.chosen, all: loaded.all };
|
|
2700
2882
|
}
|
|
@@ -2711,25 +2893,25 @@ async function rebuildIndex(path, options = {}) {
|
|
|
2711
2893
|
await store.recordInventory(inventoryRun(parsed.data, file));
|
|
2712
2894
|
replayed++;
|
|
2713
2895
|
}
|
|
2714
|
-
const
|
|
2896
|
+
const failed2 = [];
|
|
2715
2897
|
let projects = 0;
|
|
2716
2898
|
const gone = [];
|
|
2717
2899
|
for (const source of sources.projects) {
|
|
2718
2900
|
if (!await stat2(source.root).then((s) => s.isDirectory(), () => false)) {
|
|
2719
2901
|
gone.push(source.root);
|
|
2720
|
-
|
|
2902
|
+
failed2.push({ root: source.root, reason: "folder not found (moved or deleted), skipped" });
|
|
2721
2903
|
continue;
|
|
2722
2904
|
}
|
|
2723
2905
|
try {
|
|
2724
2906
|
const project2 = await loadProject(source.root, source.options);
|
|
2725
|
-
const usage = ScanReport.safeParse(await readJson(source.usage ??
|
|
2907
|
+
const usage = ScanReport.safeParse(await readJson(source.usage ?? join17(project2.root, ".youi/usage.json")));
|
|
2726
2908
|
await recordProject(store, project2, usage.success ? usage.data : null);
|
|
2727
2909
|
projects++;
|
|
2728
2910
|
} catch (error) {
|
|
2729
|
-
|
|
2911
|
+
failed2.push({ root: source.root, reason: error instanceof Error ? error.message.split("\n")[0] : String(error) });
|
|
2730
2912
|
}
|
|
2731
2913
|
}
|
|
2732
|
-
const broken =
|
|
2914
|
+
const broken = failed2.filter((f) => !gone.includes(f.root));
|
|
2733
2915
|
if (broken.length) throw new Error(`Index rebuild failed: ${broken.map((f) => `${f.root}: ${f.reason}`).join("; ")}`);
|
|
2734
2916
|
await linkCandidates(store);
|
|
2735
2917
|
const tables = (await store.stats()).tables;
|
|
@@ -2753,7 +2935,7 @@ async function rebuildIndex(path, options = {}) {
|
|
|
2753
2935
|
throw error;
|
|
2754
2936
|
}
|
|
2755
2937
|
}
|
|
2756
|
-
return { location: scratch ? path : store.location, discover, scans: log.length, inventories: { replayed, missing }, projects: { replayed: projects, failed }, tables, durationMs: Math.round(performance.now() - started) };
|
|
2938
|
+
return { location: scratch ? path : store.location, discover, scans: log.length, inventories: { replayed, missing }, projects: { replayed: projects, failed: failed2 }, tables, durationMs: Math.round(performance.now() - started) };
|
|
2757
2939
|
} finally {
|
|
2758
2940
|
if (scratch) {
|
|
2759
2941
|
await store.close();
|
|
@@ -2939,9 +3121,9 @@ function renderAdoptionRequest(request) {
|
|
|
2939
3121
|
}
|
|
2940
3122
|
|
|
2941
3123
|
// ../cli/src/report/run.ts
|
|
2942
|
-
import { randomBytes as
|
|
3124
|
+
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
2943
3125
|
import { mkdir as mkdir5, rename as rename3, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
|
|
2944
|
-
import { join as
|
|
3126
|
+
import { join as join24, relative as relative10, resolve as resolve14 } from "node:path";
|
|
2945
3127
|
|
|
2946
3128
|
// ../cli/src/report/card.ts
|
|
2947
3129
|
import { deflateSync } from "node:zlib";
|
|
@@ -3177,7 +3359,7 @@ function drawCard(input) {
|
|
|
3177
3359
|
|
|
3178
3360
|
// ../cli/src/report/model.ts
|
|
3179
3361
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
3180
|
-
import { join as
|
|
3362
|
+
import { join as join21 } from "node:path";
|
|
3181
3363
|
|
|
3182
3364
|
// ../cli/src/report/filters.ts
|
|
3183
3365
|
var SHOWCASE_GLOBS = ["**/{__stories__,.storybook,storybook,storybook-static,example,examples,demo,demos,playground,showcase,showcases}/**", "**/*.stories.*", "**/*.story.*"];
|
|
@@ -3304,11 +3486,11 @@ function publicLook(caption) {
|
|
|
3304
3486
|
|
|
3305
3487
|
// ../cli/src/report/groups.ts
|
|
3306
3488
|
import { existsSync as existsSync3 } from "node:fs";
|
|
3307
|
-
import { join as
|
|
3489
|
+
import { join as join19 } from "node:path";
|
|
3308
3490
|
|
|
3309
3491
|
// ../cli/src/report/imports.ts
|
|
3310
3492
|
import { realpathSync } from "node:fs";
|
|
3311
|
-
import { dirname as
|
|
3493
|
+
import { dirname as dirname11, join as join18, relative as relative9, resolve as resolve12 } from "node:path";
|
|
3312
3494
|
import ts from "typescript";
|
|
3313
3495
|
var resolvers = /* @__PURE__ */ new Map();
|
|
3314
3496
|
function resolverOf(root) {
|
|
@@ -3316,7 +3498,7 @@ function resolverOf(root) {
|
|
|
3316
3498
|
if (!found) {
|
|
3317
3499
|
const config = ts.findConfigFile(root, ts.sys.fileExists, "tsconfig.json") ?? ts.findConfigFile(root, ts.sys.fileExists, "jsconfig.json");
|
|
3318
3500
|
const read = config ? ts.readConfigFile(config, ts.sys.readFile) : null;
|
|
3319
|
-
const options = config && read && !read.error ? ts.parseJsonConfigFileContent(read.config, ts.sys,
|
|
3501
|
+
const options = config && read && !read.error ? ts.parseJsonConfigFileContent(read.config, ts.sys, dirname11(config)).options : {};
|
|
3320
3502
|
found = { options, cache: ts.createModuleResolutionCache(root, (name) => name, options) };
|
|
3321
3503
|
resolvers.set(root, found);
|
|
3322
3504
|
}
|
|
@@ -3327,13 +3509,13 @@ function clearImportCache() {
|
|
|
3327
3509
|
}
|
|
3328
3510
|
async function verifiedImport(root, keeper, from, suggested) {
|
|
3329
3511
|
const { options, cache } = resolverOf(root);
|
|
3330
|
-
let local =
|
|
3512
|
+
let local = relative9(dirname11(join18(root, from)), join18(root, keeper)).replaceAll("\\", "/").replace(/\.(tsx?|jsx?|mjs)$/, "");
|
|
3331
3513
|
if (!local.startsWith(".")) local = `./${local}`;
|
|
3332
3514
|
for (const specifier of /* @__PURE__ */ new Set([suggested, local])) {
|
|
3333
|
-
const found = ts.resolveModuleName(specifier,
|
|
3515
|
+
const found = ts.resolveModuleName(specifier, resolve12(root, from), options, ts.sys, cache).resolvedModule?.resolvedFileName;
|
|
3334
3516
|
if (found) {
|
|
3335
3517
|
try {
|
|
3336
|
-
if (realpathSync(found) === realpathSync(
|
|
3518
|
+
if (realpathSync(found) === realpathSync(join18(root, keeper))) return specifier;
|
|
3337
3519
|
} catch {
|
|
3338
3520
|
}
|
|
3339
3521
|
}
|
|
@@ -3741,7 +3923,7 @@ function factsOf(project2, id, modules, eligible, workspaceNames, dependencies,
|
|
|
3741
3923
|
if (dirs.has(file.slice(0, at))) break;
|
|
3742
3924
|
dirs.add(file.slice(0, at));
|
|
3743
3925
|
}
|
|
3744
|
-
const roots = [...dirs].filter((dir) => existsSync3(
|
|
3926
|
+
const roots = [...dirs].filter((dir) => existsSync3(join19(project2.root, dir, "package.json"))).sort((a, b) => b.length - a.length);
|
|
3745
3927
|
const nested = (file) => roots.find((dir) => file.startsWith(`${dir}/`)) ?? "";
|
|
3746
3928
|
return { project: project2, id, dependencies, packageImports, jsxCounts, eligible, twins, dirs, importer, packageOf: nested };
|
|
3747
3929
|
}
|
|
@@ -3749,11 +3931,11 @@ function factsOf(project2, id, modules, eligible, workspaceNames, dependencies,
|
|
|
3749
3931
|
// ../cli/src/report/projects.ts
|
|
3750
3932
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
3751
3933
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
3752
|
-
import { basename as basename4, join as
|
|
3934
|
+
import { basename as basename4, join as join20, resolve as resolve13 } from "node:path";
|
|
3753
3935
|
var UI_FILES = ["**/*.{tsx,jsx,astro,vue,svelte}"];
|
|
3754
3936
|
var strings = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
3755
3937
|
async function workspaceGlobs(root, pkg) {
|
|
3756
|
-
const pnpm = await readFile7(
|
|
3938
|
+
const pnpm = await readFile7(join20(root, "pnpm-workspace.yaml"), "utf8").catch(() => null);
|
|
3757
3939
|
if (pnpm !== null) {
|
|
3758
3940
|
try {
|
|
3759
3941
|
const globs2 = strings((0, import_yaml3.parse)(pnpm)?.packages);
|
|
@@ -3767,8 +3949,8 @@ async function workspaceGlobs(root, pkg) {
|
|
|
3767
3949
|
}
|
|
3768
3950
|
var hasUi = async (dir) => (await findFiles(dir, UI_FILES, DEFAULT_EXCLUDE)).length > 0;
|
|
3769
3951
|
async function findProjects(dir) {
|
|
3770
|
-
const root =
|
|
3771
|
-
const pkg = await readJson(
|
|
3952
|
+
const root = resolve13(dir);
|
|
3953
|
+
const pkg = await readJson(join20(root, "package.json"));
|
|
3772
3954
|
const name = typeof pkg?.name === "string" && pkg.name.trim() ? pkg.name.trim() : basename4(root);
|
|
3773
3955
|
const single = { dir: ".", root, name: typeof pkg?.name === "string" ? pkg.name : null };
|
|
3774
3956
|
const workspace = await workspaceGlobs(root, pkg);
|
|
@@ -3779,12 +3961,12 @@ async function findProjects(dir) {
|
|
|
3779
3961
|
const projects = [];
|
|
3780
3962
|
const skipped = [];
|
|
3781
3963
|
for (const member of members) {
|
|
3782
|
-
const memberRoot =
|
|
3964
|
+
const memberRoot = join20(root, member);
|
|
3783
3965
|
if (!await hasUi(memberRoot)) {
|
|
3784
3966
|
skipped.push(member);
|
|
3785
3967
|
continue;
|
|
3786
3968
|
}
|
|
3787
|
-
const memberPkg = await readJson(
|
|
3969
|
+
const memberPkg = await readJson(join20(memberRoot, "package.json"));
|
|
3788
3970
|
projects.push({ dir: member, root: memberRoot, name: typeof memberPkg?.name === "string" ? memberPkg.name : null });
|
|
3789
3971
|
}
|
|
3790
3972
|
if (projects.length === 0) return { root, name, layout: `one project (${workspace.source} names no package with UI files)`, projects: [single], skipped };
|
|
@@ -3811,7 +3993,7 @@ var Lines = class {
|
|
|
3811
3993
|
if (!this.enabled) return { at };
|
|
3812
3994
|
let lines = this.files.get(file);
|
|
3813
3995
|
if (!lines) {
|
|
3814
|
-
lines = (await readFile8(
|
|
3996
|
+
lines = (await readFile8(join21(this.root, file), "utf8").catch(() => "")).split("\n");
|
|
3815
3997
|
this.files.set(file, lines);
|
|
3816
3998
|
}
|
|
3817
3999
|
const code = lines[line - 1]?.trim();
|
|
@@ -3826,15 +4008,15 @@ function hardcodedValue(finding3) {
|
|
|
3826
4008
|
const value = bracket ?? (declaration ? `${declaration[2]} (${declaration[1]})` : finding3.text);
|
|
3827
4009
|
return { word: word === "type" ? "text size" : word, value, tokens };
|
|
3828
4010
|
}
|
|
3829
|
-
async function modulesOf(project2, target,
|
|
4011
|
+
async function modulesOf(project2, target, failed2) {
|
|
3830
4012
|
const modules = [];
|
|
3831
4013
|
for (const file of target.files) {
|
|
3832
4014
|
if (isShowcase(file)) continue;
|
|
3833
4015
|
try {
|
|
3834
|
-
const module = await parseModule(file, await readFile8(
|
|
4016
|
+
const module = await parseModule(file, await readFile8(join21(project2.root, file), "utf8"));
|
|
3835
4017
|
if (module) modules.push(module);
|
|
3836
4018
|
} catch (error) {
|
|
3837
|
-
|
|
4019
|
+
failed2.push(`${repoPath(project2.dir, file)}: ${errorText(error)}`);
|
|
3838
4020
|
}
|
|
3839
4021
|
}
|
|
3840
4022
|
return modules;
|
|
@@ -3855,7 +4037,7 @@ async function grouped(project2, found, lines, describe) {
|
|
|
3855
4037
|
return findings2.sort((a, b) => b.count - a.count || a.title.localeCompare(b.title));
|
|
3856
4038
|
}
|
|
3857
4039
|
async function analyseProject(project2, index, inventory, inventoryError, workspaceNames, lines) {
|
|
3858
|
-
const
|
|
4040
|
+
const failed2 = [];
|
|
3859
4041
|
const incomplete = [];
|
|
3860
4042
|
const notes = [];
|
|
3861
4043
|
const projectId = inventory?.projects[index]?.id;
|
|
@@ -3863,7 +4045,7 @@ async function analyseProject(project2, index, inventory, inventoryError, worksp
|
|
|
3863
4045
|
let target = null;
|
|
3864
4046
|
try {
|
|
3865
4047
|
target = await loadInventoryTarget(project2.root);
|
|
3866
|
-
modules = await modulesOf(project2, target,
|
|
4048
|
+
modules = await modulesOf(project2, target, failed2);
|
|
3867
4049
|
} catch (error) {
|
|
3868
4050
|
incomplete.push(`The code could not be read (${errorText(error)})`);
|
|
3869
4051
|
}
|
|
@@ -3906,7 +4088,7 @@ async function analyseProject(project2, index, inventory, inventoryError, worksp
|
|
|
3906
4088
|
const components = [...byComponent.values()].map((c) => ({ name: c.name, file: c.file, uses: c.roles.length, role: [...new Set(c.roles)].sort((a, b) => c.roles.filter((r) => r === b).length - c.roles.filter((r) => r === a).length)[0] })).sort((a, b) => b.uses - a.uses || a.name.localeCompare(b.name)).slice(0, TOP_COMPONENTS);
|
|
3907
4089
|
const inventoryProject = inventory?.projects[index];
|
|
3908
4090
|
if (inventoryError) incomplete.push(`The component inventory could not be built (${inventoryError}); run ${NPX} inventory --project ${project2.dir} to see why`);
|
|
3909
|
-
for (const f of inventoryProject?.failed ?? [])
|
|
4091
|
+
for (const f of inventoryProject?.failed ?? []) failed2.push(`${repoPath(project2.dir, f.file)}: ${f.reason}`);
|
|
3910
4092
|
let hardcoded = [];
|
|
3911
4093
|
let offLibrary = [];
|
|
3912
4094
|
const everyLine = () => true;
|
|
@@ -3935,7 +4117,7 @@ async function analyseProject(project2, index, inventory, inventoryError, worksp
|
|
|
3935
4117
|
incomplete.push(`Library choices were not compared (${errorText(error)}); run ${NPX} detect ${project2.dir} to see why`);
|
|
3936
4118
|
}
|
|
3937
4119
|
}
|
|
3938
|
-
const pkg = await readFile8(
|
|
4120
|
+
const pkg = await readFile8(join21(project2.root, "package.json"), "utf8").then((text) => JSON.parse(text), () => null);
|
|
3939
4121
|
const dependencies = new Set(["dependencies", "devDependencies", "peerDependencies"].flatMap((key2) => Object.keys(pkg?.[key2] ?? {})));
|
|
3940
4122
|
const importer = changeProject ? await importOf(changeProject) : () => "";
|
|
3941
4123
|
const facts = factsOf(project2, projectId ?? null, modules, eligible, workspaceNames, dependencies, target?.files ?? [], importer);
|
|
@@ -3943,7 +4125,7 @@ async function analyseProject(project2, index, inventory, inventoryError, worksp
|
|
|
3943
4125
|
dir: project2.dir,
|
|
3944
4126
|
name: project2.name,
|
|
3945
4127
|
files: inventoryProject?.files ?? modules.length,
|
|
3946
|
-
failed,
|
|
4128
|
+
failed: failed2,
|
|
3947
4129
|
libraries,
|
|
3948
4130
|
unused,
|
|
3949
4131
|
definitions: inventory ? inventory.definitions.filter((d) => d.project === projectId && !isShowcase(d.file)).length : 0,
|
|
@@ -4379,36 +4561,36 @@ ${model.projects.map((p) => projectSection(p, many, looks)).join("\n")}
|
|
|
4379
4561
|
import { spawn as spawn2 } from "node:child_process";
|
|
4380
4562
|
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "node:fs";
|
|
4381
4563
|
import { homedir as homedir2 } from "node:os";
|
|
4382
|
-
import { dirname as
|
|
4564
|
+
import { dirname as dirname12, join as join22 } from "node:path";
|
|
4383
4565
|
var LOOKS_PER_PROJECT = 4;
|
|
4384
4566
|
var DOWNLOAD_SIZE = "~100 MB";
|
|
4385
4567
|
var DEPENDENCIES = "Install the repo's dependencies to see rendered looks";
|
|
4386
4568
|
var UNDRAWABLE = /not installed|loads no stylesheet|drawn from (?:its|their) (?:tag and )?classes|did not render|bundle failed|unstyled|stub fallback/i;
|
|
4387
|
-
var playwrightDir = () =>
|
|
4569
|
+
var playwrightDir = () => dirname12(playwrightCli());
|
|
4388
4570
|
function browsersPath(env) {
|
|
4389
4571
|
const set = env.PLAYWRIGHT_BROWSERS_PATH;
|
|
4390
|
-
if (set === "0") return
|
|
4572
|
+
if (set === "0") return join22(playwrightDir(), ".local-browsers");
|
|
4391
4573
|
if (set) return set;
|
|
4392
|
-
if (process.platform === "darwin") return
|
|
4393
|
-
if (process.platform === "win32") return
|
|
4394
|
-
return
|
|
4574
|
+
if (process.platform === "darwin") return join22(homedir2(), "Library/Caches/ms-playwright");
|
|
4575
|
+
if (process.platform === "win32") return join22(env.LOCALAPPDATA ?? join22(homedir2(), "AppData/Local"), "ms-playwright");
|
|
4576
|
+
return join22(env.XDG_CACHE_HOME ?? join22(homedir2(), ".cache"), "ms-playwright");
|
|
4395
4577
|
}
|
|
4396
4578
|
function chromiumStatus(env = process.env) {
|
|
4397
4579
|
if (env.YOUI_CHROMIUM) return { available: existsSync4(env.YOUI_CHROMIUM), where: env.YOUI_CHROMIUM };
|
|
4398
4580
|
try {
|
|
4399
|
-
const browsers = JSON.parse(readFileSync2(
|
|
4581
|
+
const browsers = JSON.parse(readFileSync2(join22(playwrightDir(), "browsers.json"), "utf8"));
|
|
4400
4582
|
const revision2 = browsers.browsers.find((b) => b.name === "chromium-headless-shell")?.revision;
|
|
4401
|
-
const dir =
|
|
4402
|
-
return { available: revision2 !== void 0 && existsSync4(
|
|
4583
|
+
const dir = join22(browsersPath(env), `chromium_headless_shell-${revision2}`);
|
|
4584
|
+
return { available: revision2 !== void 0 && existsSync4(join22(dir, "INSTALLATION_COMPLETE")), where: dir };
|
|
4403
4585
|
} catch {
|
|
4404
4586
|
return { available: false, where: "playwright-core is not installed" };
|
|
4405
4587
|
}
|
|
4406
4588
|
}
|
|
4407
4589
|
function downloadChromium() {
|
|
4408
|
-
return new Promise((
|
|
4409
|
-
const child = spawn2(process.execPath, [
|
|
4410
|
-
child.on("error", () =>
|
|
4411
|
-
child.on("close", (code) =>
|
|
4590
|
+
return new Promise((resolve16) => {
|
|
4591
|
+
const child = spawn2(process.execPath, [join22(playwrightDir(), "cli.js"), "install", "chromium-headless-shell"], { stdio: ["ignore", 2, 2] });
|
|
4592
|
+
child.on("error", () => resolve16(false));
|
|
4593
|
+
child.on("close", (code) => resolve16(code === 0));
|
|
4412
4594
|
});
|
|
4413
4595
|
}
|
|
4414
4596
|
var dataUri = (file) => file && existsSync4(file) ? `data:image/png;base64,${readFileSync2(file).toString("base64")}` : null;
|
|
@@ -4422,24 +4604,24 @@ async function addLooks(model, repoRoot, options = {}) {
|
|
|
4422
4604
|
const where2 = section.dir === "." ? "this repo" : section.dir;
|
|
4423
4605
|
try {
|
|
4424
4606
|
const installed = (name) => {
|
|
4425
|
-
let dir =
|
|
4607
|
+
let dir = join22(repoRoot, section.dir);
|
|
4426
4608
|
while (true) {
|
|
4427
|
-
if (existsSync4(
|
|
4428
|
-
if (dir === repoRoot ||
|
|
4429
|
-
dir =
|
|
4609
|
+
if (existsSync4(join22(dir, "node_modules", name, "package.json"))) return true;
|
|
4610
|
+
if (dir === repoRoot || dirname12(dir) === dir) return false;
|
|
4611
|
+
dir = dirname12(dir);
|
|
4430
4612
|
}
|
|
4431
4613
|
};
|
|
4432
4614
|
if (!installed("react") || !installed("react-dom")) {
|
|
4433
4615
|
missing.push(where2);
|
|
4434
4616
|
continue;
|
|
4435
4617
|
}
|
|
4436
|
-
const projectRoot =
|
|
4618
|
+
const projectRoot = join22(repoRoot, section.dir);
|
|
4437
4619
|
const target = await loadInventoryTarget(projectRoot);
|
|
4438
4620
|
if (findStylesheets(projectRoot, target.files, { tsconfig: target.tsconfig, override: target.specimenCss, templates: target.templates }).found.length === 0) {
|
|
4439
4621
|
missing.push(where2);
|
|
4440
4622
|
continue;
|
|
4441
4623
|
}
|
|
4442
|
-
const report = await renderShots(
|
|
4624
|
+
const report = await renderShots(join22(repoRoot, section.dir), names, { download: false, base: "HEAD", ...options.executablePath ? { executablePath: options.executablePath } : {}, ...options.cache ? { cache: options.cache } : {}, ...options.log ? { log: options.log } : {} });
|
|
4443
4625
|
const unavailable = report.notes.some((note) => UNDRAWABLE.test(note));
|
|
4444
4626
|
if (unavailable) {
|
|
4445
4627
|
missing.push(where2);
|
|
@@ -4511,7 +4693,7 @@ function renderMarkdown(model, reportFile) {
|
|
|
4511
4693
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
4512
4694
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
4513
4695
|
import { homedir as homedir3, userInfo as userInfo2 } from "node:os";
|
|
4514
|
-
import { join as
|
|
4696
|
+
import { join as join23 } from "node:path";
|
|
4515
4697
|
var REDACTED = "[redacted]";
|
|
4516
4698
|
var OUTSIDE = "[path outside the repo]";
|
|
4517
4699
|
var MIN_VALUE = 6;
|
|
@@ -4523,7 +4705,7 @@ async function dotenvValues(root) {
|
|
|
4523
4705
|
const files = await findFiles(root, [".env", ".env.*", "**/.env", "**/.env.*"]).catch(() => []);
|
|
4524
4706
|
const values = [];
|
|
4525
4707
|
for (const file of files) {
|
|
4526
|
-
const text = await readFile9(
|
|
4708
|
+
const text = await readFile9(join23(root, file), "utf8").catch(() => "");
|
|
4527
4709
|
for (const line of text.split(/\r?\n/)) {
|
|
4528
4710
|
const match = /^\s*(?:export\s+)?[A-Za-z_][A-Za-z0-9_.-]*\s*=\s*(.*)$/.exec(line);
|
|
4529
4711
|
if (!match) continue;
|
|
@@ -4650,12 +4832,12 @@ async function askTerminal(question) {
|
|
|
4650
4832
|
}
|
|
4651
4833
|
}
|
|
4652
4834
|
async function writeBinaryAtomic(file, bytes) {
|
|
4653
|
-
const temp = `${file}.${process.pid}.${
|
|
4835
|
+
const temp = `${file}.${process.pid}.${randomBytes3(6).toString("hex")}.tmp`;
|
|
4654
4836
|
await writeFile2(temp, bytes);
|
|
4655
4837
|
await rename3(temp, file);
|
|
4656
4838
|
}
|
|
4657
4839
|
var shown = (file) => {
|
|
4658
|
-
const rel =
|
|
4840
|
+
const rel = relative10(process.cwd(), file);
|
|
4659
4841
|
return rel && !rel.startsWith("..") ? rel : file;
|
|
4660
4842
|
};
|
|
4661
4843
|
async function runReport(options = {}, io = {}) {
|
|
@@ -4664,7 +4846,7 @@ async function runReport(options = {}, io = {}) {
|
|
|
4664
4846
|
const error = io.error ?? ((text) => void process.stderr.write(`${text}
|
|
4665
4847
|
`));
|
|
4666
4848
|
const env = io.env ?? process.env;
|
|
4667
|
-
const root =
|
|
4849
|
+
const root = resolve14(options.path ?? process.cwd());
|
|
4668
4850
|
if (!(await stat3(root).catch(() => null))?.isDirectory()) {
|
|
4669
4851
|
error(`\u2716 ${options.path ?? root} is not a directory: run ${NPX} in a repo, or pass its path (${NPX} path/to/repo)`);
|
|
4670
4852
|
return { code: 2, files: null, model: null };
|
|
@@ -4694,9 +4876,9 @@ async function runReport(options = {}, io = {}) {
|
|
|
4694
4876
|
model.durationMs += Math.round(performance.now() - started);
|
|
4695
4877
|
const redactor = await Redactor.forRepo(root, { includeCode: options.includeCode === true, env });
|
|
4696
4878
|
const clean = redactor.model(model);
|
|
4697
|
-
const outDir =
|
|
4879
|
+
const outDir = resolve14(options.out ?? root);
|
|
4698
4880
|
await mkdir5(outDir, { recursive: true });
|
|
4699
|
-
const files = { report:
|
|
4881
|
+
const files = { report: join24(outDir, REPORT_FILE), card: join24(outDir, CARD_FILE), summary: join24(outDir, SUMMARY_FILE) };
|
|
4700
4882
|
const t = clean.totals;
|
|
4701
4883
|
const card = {
|
|
4702
4884
|
repo: redactor.scrub(clean.repo),
|
|
@@ -4780,6 +4962,11 @@ ${style.bold("Anywhere")} ${style.dim("no design system needed")}
|
|
|
4780
4962
|
an unchanged component comes from the cache (YOUI_SPECIMEN_CACHE)
|
|
4781
4963
|
|
|
4782
4964
|
${style.bold("In a product repo")}
|
|
4965
|
+
status [--json] where the product stands with its design system, in a few lines: the System
|
|
4966
|
+
and its source, what a sync would change (a dry run, offline), local drift,
|
|
4967
|
+
errors and warnings (beyond the baseline), components used, open requests,
|
|
4968
|
+
and the one thing to do next. In a workspace (youi.workspace.json, or a repo
|
|
4969
|
+
holding several products), one block per product
|
|
4783
4970
|
adopt [--components dir] [--css file] [--system id] [--fork] [--dry-run]
|
|
4784
4971
|
make this product's own UI its design system, kept in this repo: a draft
|
|
4785
4972
|
contract per component in the components folder (the files stay where they
|
|
@@ -4883,7 +5070,8 @@ ${style.bold("Detect")} ${style.dim("which UI libraries a repo or website uses
|
|
|
4883
5070
|
|
|
4884
5071
|
${style.bold("The hub")}
|
|
4885
5072
|
ui [--design dir] [--project dir] [--config file] [--root dir] [--port n] [--watch] [--state dir] [--inventory file] [--detect file]
|
|
4886
|
-
open the web hub on a design system (default: the demo system
|
|
5073
|
+
open the web hub on a design system (default: the demo system; beside a
|
|
5074
|
+
youi.workspace.json, its products, with Work > Workspace to switch);
|
|
4887
5075
|
--project adds that product's usage map (read-only scan) and the
|
|
4888
5076
|
rule editor (System > Rules, Work > Changes): drafts, impact preview,
|
|
4889
5077
|
approval, a review branch in the design repo (drafts kept in --state);
|
|
@@ -4992,10 +5180,10 @@ async function readJsonOrFile(value) {
|
|
|
4992
5180
|
async function cmdScan(values) {
|
|
4993
5181
|
const p = await project(values);
|
|
4994
5182
|
const { report } = await scanProject(p);
|
|
4995
|
-
const out = values.out ??
|
|
4996
|
-
await writeFileAtomic(
|
|
5183
|
+
const out = values.out ?? join25(p.root, ".youi/usage.json");
|
|
5184
|
+
await writeFileAtomic(resolve15(out), `${JSON.stringify(report)}
|
|
4997
5185
|
`);
|
|
4998
|
-
const recorded = await recordUsage(values, p, report,
|
|
5186
|
+
const recorded = await recordUsage(values, p, report, resolve15(out));
|
|
4999
5187
|
if (values.json) json3(report);
|
|
5000
5188
|
else print([renderScan(report, out), ...recorded ? [recorded] : []].join("\n"));
|
|
5001
5189
|
return 0;
|
|
@@ -5004,7 +5192,7 @@ async function recordUsage(values, p, report, usage) {
|
|
|
5004
5192
|
const { path, home } = indexOf(values);
|
|
5005
5193
|
try {
|
|
5006
5194
|
await recordProject(await sharedStore(path), p, report);
|
|
5007
|
-
await noteSource(home, { project: { root:
|
|
5195
|
+
await noteSource(home, { project: { root: resolve15(values.project ?? process.cwd()), options: Object.fromEntries(Object.entries(loadOptions(values)).map(([key2, value]) => [key2, resolve15(value)])), usage } });
|
|
5008
5196
|
return null;
|
|
5009
5197
|
} catch (error) {
|
|
5010
5198
|
return notRecorded(error);
|
|
@@ -5019,17 +5207,17 @@ function indexOf(values) {
|
|
|
5019
5207
|
}
|
|
5020
5208
|
async function cmdGaps(values) {
|
|
5021
5209
|
const dirs = inventoryDirs(values);
|
|
5022
|
-
const inventory = values.inventory ? InventoryReport.parse(JSON.parse(await readFile10(
|
|
5023
|
-
const cwd = values.inventory ?
|
|
5024
|
-
const project2 = await loadProject(
|
|
5210
|
+
const inventory = values.inventory ? InventoryReport.parse(JSON.parse(await readFile10(resolve15(values.inventory), "utf8"))) : await scanInventory(values, dirs);
|
|
5211
|
+
const cwd = values.inventory ? dirname13(resolve15(values.inventory)) : process.cwd();
|
|
5212
|
+
const project2 = await loadProject(resolve15(dirs[0]), loadOptions(values)).catch(() => null);
|
|
5025
5213
|
const system = project2 ? { name: project2.system.config.name, components: project2.system.components.map((c) => c.contract.name) } : null;
|
|
5026
|
-
const store = await readCatalog(
|
|
5214
|
+
const store = await readCatalog(resolve15(discoverCacheDir(values.cache)), indexOf(values).path).catch((error) => {
|
|
5027
5215
|
if (error instanceof MissingIndexError) return null;
|
|
5028
5216
|
throw error;
|
|
5029
5217
|
});
|
|
5030
|
-
const roots = new Map(inventory.projects.map((p) => [p.id,
|
|
5218
|
+
const roots = new Map(inventory.projects.map((p) => [p.id, resolve15(cwd, p.root)]));
|
|
5031
5219
|
const report = await buildGaps({ inventory, system, dependencies: declaredPackages(roots) }, store);
|
|
5032
|
-
if (values.out) await writeFileAtomic(
|
|
5220
|
+
if (values.out) await writeFileAtomic(resolve15(values.out), `${JSON.stringify(report, null, 2)}
|
|
5033
5221
|
`);
|
|
5034
5222
|
if (values.json) json3(report);
|
|
5035
5223
|
else print(renderGaps(report));
|
|
@@ -5039,12 +5227,12 @@ async function cmdInventory(values) {
|
|
|
5039
5227
|
if (values.history) return cmdHistory(values, []);
|
|
5040
5228
|
const dirs = inventoryDirs(values);
|
|
5041
5229
|
const report = await scanInventory(values, dirs);
|
|
5042
|
-
const out =
|
|
5230
|
+
const out = resolve15(values.out ?? join25(dirs[0], ".youi/inventory.json"));
|
|
5043
5231
|
await writeFileAtomic(out, `${JSON.stringify(report, null, 2)}
|
|
5044
5232
|
`);
|
|
5045
5233
|
const recorded = await recordScan(values, report, out);
|
|
5046
5234
|
if (values.json) json3(report);
|
|
5047
|
-
else print([renderInventory(report,
|
|
5235
|
+
else print([renderInventory(report, relative11(process.cwd(), out).startsWith("..") ? out : relative11(process.cwd(), out)), recorded].join("\n"));
|
|
5048
5236
|
return 0;
|
|
5049
5237
|
}
|
|
5050
5238
|
async function recordScan(values, report, out) {
|
|
@@ -5069,7 +5257,7 @@ async function cmdIndex(values, positionals) {
|
|
|
5069
5257
|
const [action, ...rest] = positionals;
|
|
5070
5258
|
const { path, home } = indexOf(values);
|
|
5071
5259
|
if (action === "path") {
|
|
5072
|
-
if (values.json) json3({ store: storeLocation({ path }), sources:
|
|
5260
|
+
if (values.json) json3({ store: storeLocation({ path }), sources: join25(home, SOURCES_FILE), scans: join25(home, SCANS_LOG) });
|
|
5073
5261
|
else print(storeLocation({ path }));
|
|
5074
5262
|
return 0;
|
|
5075
5263
|
}
|
|
@@ -5080,7 +5268,7 @@ async function cmdIndex(values, positionals) {
|
|
|
5080
5268
|
return 0;
|
|
5081
5269
|
}
|
|
5082
5270
|
if (action === "rebuild") {
|
|
5083
|
-
const summary = await rebuildIndex(path, values.cache ? { discoverCache:
|
|
5271
|
+
const summary = await rebuildIndex(path, values.cache ? { discoverCache: resolve15(values.cache) } : {});
|
|
5084
5272
|
if (values.json) json3(summary);
|
|
5085
5273
|
else print(renderRebuild(summary));
|
|
5086
5274
|
return 0;
|
|
@@ -5120,7 +5308,7 @@ async function cmdBom(values, positionals) {
|
|
|
5120
5308
|
return 0;
|
|
5121
5309
|
}
|
|
5122
5310
|
function baselineFile(values, p) {
|
|
5123
|
-
if (values["baseline-file"]) return
|
|
5311
|
+
if (values["baseline-file"]) return resolve15(values["baseline-file"]);
|
|
5124
5312
|
return values.baseline ? baselinePath(p, values.config) : null;
|
|
5125
5313
|
}
|
|
5126
5314
|
var checkScope = (values, positionals) => ({ ...positionals.length > 0 ? { files: positionals } : {}, ...values.rule ? { rule: values.rule } : {}, quiet: values.quiet });
|
|
@@ -5177,7 +5365,7 @@ async function cmdBaseline(values) {
|
|
|
5177
5365
|
const { totals } = written.baseline;
|
|
5178
5366
|
if (values.json) json3({ file: written.file, action: written.action, totals, notAdded: written.notAdded, identity: written.baseline.identity });
|
|
5179
5367
|
else {
|
|
5180
|
-
print(`${style.ok(written.action)} ${
|
|
5368
|
+
print(`${style.ok(written.action)} ${relative11(process.cwd(), file) || file}: ${plural(totals.errors, "error")} \xB7 ${plural(totals.warnings, "warning")} accepted`);
|
|
5181
5369
|
print(style.dim(` rules ${describeIdentity(written.baseline.identity)}`));
|
|
5182
5370
|
if (written.notAdded > 0) print(style.warn(` ${plural(written.notAdded, "current violation")} not added: fix them, or accept them deliberately with --force`));
|
|
5183
5371
|
}
|
|
@@ -5248,7 +5436,7 @@ async function cmdInit(values) {
|
|
|
5248
5436
|
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)");
|
|
5249
5437
|
const root = values.project ?? process.cwd();
|
|
5250
5438
|
const design = await designArg(values.design, root);
|
|
5251
|
-
const result = await initProject({ root, ...design, schemaDir:
|
|
5439
|
+
const result = await initProject({ root, ...design, schemaDir: join25(TOOL_ROOT, "schema"), ...values.system ? { system: values.system } : {}, ...values.components ? { componentsDir: values.components } : {}, force: values.force });
|
|
5252
5440
|
if (!values.json) {
|
|
5253
5441
|
print(`${style.ok("created")} ${result.file}`);
|
|
5254
5442
|
for (const note of result.notes) print(style.dim(` \xB7 ${note}`));
|
|
@@ -5258,28 +5446,28 @@ async function cmdInit(values) {
|
|
|
5258
5446
|
return cmdSync({ ...design.package ? rest : values, project: root });
|
|
5259
5447
|
}
|
|
5260
5448
|
async function cmdAdopt(values) {
|
|
5261
|
-
const root =
|
|
5262
|
-
if (await exists(
|
|
5449
|
+
const root = resolve15(values.project ?? process.cwd());
|
|
5450
|
+
if (await exists(join25(root, PROJECT_FILE))) throw new Error(`${root} already has ${PROJECT_FILE}: it follows a design system already (youiyoux sync updates it)`);
|
|
5263
5451
|
const plan = await planAdoption({ root, ...values.components ? { componentsDir: values.components } : {}, ...values.css ? { css: values.css } : {}, ...values.system ? { system: values.system } : {}, fork: values.fork });
|
|
5264
|
-
const taken = (await Promise.all(plan.files.map(async (f) => await exists(
|
|
5452
|
+
const taken = (await Promise.all(plan.files.map(async (f) => await exists(join25(root, f.path)) ? f.path : null))).filter((f) => f !== null);
|
|
5265
5453
|
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" : ""}`);
|
|
5266
5454
|
if (values["dry-run"]) {
|
|
5267
5455
|
if (values.json) json3(plan);
|
|
5268
5456
|
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"));
|
|
5269
5457
|
return 0;
|
|
5270
5458
|
}
|
|
5271
|
-
const stylesheet = plan.stylesheet ? await readFile10(
|
|
5459
|
+
const stylesheet = plan.stylesheet ? await readFile10(join25(root, plan.stylesheet.path), "utf8") : null;
|
|
5272
5460
|
try {
|
|
5273
|
-
for (const file of plan.files) await writeFileAtomic(
|
|
5274
|
-
if (plan.stylesheet) await writeFileAtomic(
|
|
5275
|
-
await initProject({ root, design: root, schemaDir:
|
|
5461
|
+
for (const file of plan.files) await writeFileAtomic(join25(root, file.path), file.content);
|
|
5462
|
+
if (plan.stylesheet) await writeFileAtomic(join25(root, plan.stylesheet.path), plan.stylesheet.content);
|
|
5463
|
+
await initProject({ root, design: root, schemaDir: join25(TOOL_ROOT, "schema"), system: plan.system.id, componentsDir: plan.componentsDir, outputs: { ...plan.outputs, targets: [...plan.outputs.targets], dark: [...plan.outputs.dark] }, tokenSources: plan.tokenSources });
|
|
5276
5464
|
await syncProject(await loadProject(root), { dryRun: true });
|
|
5277
5465
|
} catch (error) {
|
|
5278
|
-
for (const file of [...plan.files.map((f) => f.path), PROJECT_FILE]) await rm6(
|
|
5279
|
-
for (const folder of [...new Set(plan.files.map((f) =>
|
|
5280
|
-
await rmdir3(
|
|
5281
|
-
await rmdir3(
|
|
5282
|
-
if (plan.stylesheet && stylesheet !== null) await writeFileAtomic(
|
|
5466
|
+
for (const file of [...plan.files.map((f) => f.path), PROJECT_FILE]) await rm6(join25(root, file), { force: true });
|
|
5467
|
+
for (const folder of [...new Set(plan.files.map((f) => dirname13(f.path)))].sort((a, b) => b.length - a.length)) await rmdir3(join25(root, folder)).catch(() => void 0);
|
|
5468
|
+
await rmdir3(join25(root, "design/components")).catch(() => void 0);
|
|
5469
|
+
await rmdir3(join25(root, "design")).catch(() => void 0);
|
|
5470
|
+
if (plan.stylesheet && stylesheet !== null) await writeFileAtomic(join25(root, plan.stylesheet.path), stylesheet);
|
|
5283
5471
|
throw new Error(`adopt was undone, nothing kept: ${error instanceof Error ? error.message : String(error)}`);
|
|
5284
5472
|
}
|
|
5285
5473
|
if (!values.json) print([...adoptLines(plan), ""].join("\n"));
|
|
@@ -5305,6 +5493,12 @@ function adoptLines(plan, dryRun = false) {
|
|
|
5305
5493
|
})
|
|
5306
5494
|
];
|
|
5307
5495
|
}
|
|
5496
|
+
async function cmdStatus(values) {
|
|
5497
|
+
const report = await workspaceStatus(process.cwd(), values.project);
|
|
5498
|
+
if (values.json) json3(report);
|
|
5499
|
+
else print(renderStatus(report));
|
|
5500
|
+
return report.projects.length === 0 ? 1 : statusExitCode(report);
|
|
5501
|
+
}
|
|
5308
5502
|
async function cmdSystem(values, positionals) {
|
|
5309
5503
|
const [action, dir, ...extra] = positionals;
|
|
5310
5504
|
if (action !== "extract" || dir === void 0 || extra.length > 0) throw new UsageError("youiyoux system extract <dir> [--package <name>] [--dry-run] (move the System youiyoux adopt keeps in this product into a design repo of its own)");
|
|
@@ -5324,7 +5518,7 @@ async function cmdSystem(values, positionals) {
|
|
|
5324
5518
|
print([...lines, ""].join("\n"));
|
|
5325
5519
|
const synced = await cmdSync({ ...values, project: p.root, package: void 0 });
|
|
5326
5520
|
const git3 = `push it and set source to { "git": "<its url>", "ref": "v${result.system.version}" }`;
|
|
5327
|
-
print(`Next: make ${
|
|
5521
|
+
print(`Next: make ${relative11(process.cwd(), result.target) || "."} a repository of its own and commit it. For each app to follow it, ${values.package ? `publish ${values.package}, add it as a dependency and set source to { "package": "${values.package}" }, or ${git3}` : `${git3}, or publish it as an npm package (--package names it)`}. Change components there from now on: youiyoux sync merges them into each product`);
|
|
5328
5522
|
return synced;
|
|
5329
5523
|
}
|
|
5330
5524
|
async function cmdLink(values, positionals) {
|
|
@@ -5342,31 +5536,31 @@ async function cmdUnlink(values) {
|
|
|
5342
5536
|
const root = values.project ?? process.cwd();
|
|
5343
5537
|
const linked = await linkedDesign(root);
|
|
5344
5538
|
if (linked !== null) await setLink(root, null);
|
|
5345
|
-
print(linked ? `${style.ok("unlinked")} ${
|
|
5539
|
+
print(linked ? `${style.ok("unlinked")} ${resolve15(root)} uses its config's source again` : `${resolve15(root)} was not linked`);
|
|
5346
5540
|
return 0;
|
|
5347
5541
|
}
|
|
5348
5542
|
async function designArg(value, root) {
|
|
5349
|
-
if (existsSync5(
|
|
5350
|
-
return { design: await designRootOf({ package: value },
|
|
5543
|
+
if (existsSync5(resolve15(value)) || !PACKAGE_NAME.test(value)) return { design: value };
|
|
5544
|
+
return { design: await designRootOf({ package: value }, join25(resolve15(root), PROJECT_FILE), root), package: value };
|
|
5351
5545
|
}
|
|
5352
5546
|
async function cmdBuild(values) {
|
|
5353
|
-
const root =
|
|
5547
|
+
const root = resolve15(values.design ?? process.cwd());
|
|
5354
5548
|
const system = getSystem(await loadDesignRepo(root), values.system);
|
|
5355
5549
|
if (safeId(system.config.id) === null) throw new Error(`Cannot build system ${JSON.stringify(system.config.id)}: the id must be a plain name without ".." or path separators.`);
|
|
5356
5550
|
const output = OutputConfig.parse({ cssVarPrefix: values.prefix ?? "youi", targets: ["css-vars", "tailwind-v4", "ts", "react-native"] });
|
|
5357
5551
|
const started = performance.now();
|
|
5358
5552
|
const built = await buildTokens(root, system.config, output, { contracts: system.components.map((c) => c.contract) });
|
|
5359
|
-
const out =
|
|
5360
|
-
const boundary = values.out ? out :
|
|
5361
|
-
if (!within(boundary, out) || built.files.some((file) => !within(out,
|
|
5362
|
-
for (const file of built.files) await writeFileAtomic(
|
|
5553
|
+
const out = resolve15(values.out ?? join25(root, "build", system.config.id));
|
|
5554
|
+
const boundary = values.out ? out : join25(root, "build");
|
|
5555
|
+
if (!within(boundary, out) || built.files.some((file) => !within(out, join25(out, file.path)))) throw new Error(`Cannot build system ${JSON.stringify(system.config.id)}: an output path leaves the output directory.`);
|
|
5556
|
+
for (const file of built.files) await writeFileAtomic(join25(out, file.path), file.content);
|
|
5363
5557
|
if (values.json) json3({ out, files: built.files.map((f) => f.path), tokens: built.tokens.length });
|
|
5364
5558
|
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)})`)}`);
|
|
5365
5559
|
return 0;
|
|
5366
5560
|
}
|
|
5367
5561
|
async function cmdParity(values) {
|
|
5368
5562
|
if (!values.css) throw new UsageError("youiyoux parity --css <file> [--prefix p]");
|
|
5369
|
-
const root =
|
|
5563
|
+
const root = resolve15(values.design ?? process.cwd());
|
|
5370
5564
|
const system = getSystem(await loadDesignRepo(root), values.system);
|
|
5371
5565
|
const prefix = values.prefix ?? "youi";
|
|
5372
5566
|
const dark = { selector: values.dark ?? ':root[data-theme="dark"]' };
|
|
@@ -5384,16 +5578,16 @@ async function cmdParity(values) {
|
|
|
5384
5578
|
async function cmdSchema(values) {
|
|
5385
5579
|
const schemas = renderJsonSchemas();
|
|
5386
5580
|
if (values.check) {
|
|
5387
|
-
const dir =
|
|
5581
|
+
const dir = join25(values.design ? resolve15(values.design) : TOOL_ROOT, "schema");
|
|
5388
5582
|
const stale = [];
|
|
5389
|
-
for (const { file, content } of schemas) if (await readFile10(
|
|
5583
|
+
for (const { file, content } of schemas) if (await readFile10(join25(dir, file), "utf8").catch(() => null) !== content) stale.push(file);
|
|
5390
5584
|
if (values.json) json3({ dir, stale });
|
|
5391
5585
|
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>" : ""}`);
|
|
5392
5586
|
return stale.length === 0 ? 0 : 1;
|
|
5393
5587
|
}
|
|
5394
5588
|
if (values.write) {
|
|
5395
|
-
const root = values.design ?
|
|
5396
|
-
for (const { file, content } of schemas) await writeFileAtomic(
|
|
5589
|
+
const root = values.design ? resolve15(values.design) : TOOL_ROOT;
|
|
5590
|
+
for (const { file, content } of schemas) await writeFileAtomic(join25(root, "schema", file), content);
|
|
5397
5591
|
print(`${style.ok("wrote")} ${schemas.map((s) => s.file).join(", ")}`);
|
|
5398
5592
|
} else json3(Object.fromEntries(schemas.map((s) => [s.file, JSON.parse(s.content)])));
|
|
5399
5593
|
return 0;
|
|
@@ -5416,7 +5610,7 @@ async function cmdHooks(values, positionals) {
|
|
|
5416
5610
|
if (action !== "install") throw new UsageError("youiyoux hooks install [--claude] [--git] [--ci [--diff]] [--strict] or youiyoux hooks run claude|pre-commit");
|
|
5417
5611
|
const p = await loadCheckProject(values.project ?? process.cwd(), loadOptions(values), !values.project);
|
|
5418
5612
|
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");
|
|
5419
|
-
const target = { ...hookTarget(values), project: p.root, ...configured(p) && p.configFile && p.configFile !==
|
|
5613
|
+
const target = { ...hookTarget(values), project: p.root, ...configured(p) && p.configFile && p.configFile !== join25(p.root, PROJECT_FILE) ? { config: p.configFile } : {}, ...values.root !== void 0 ? { root: p.root } : {} };
|
|
5420
5614
|
const all = !values.claude && !values.git && !values.ci;
|
|
5421
5615
|
const results = [];
|
|
5422
5616
|
if (values.claude || all) results.push({ kind: "Claude Code", ...await installClaudeHook(await repoRootOf(p.root), hookCommand(TOOL_ROOT, "claude", target)) });
|
|
@@ -5431,11 +5625,11 @@ async function cmdHooks(values, positionals) {
|
|
|
5431
5625
|
async function cmdAgents(values, positionals) {
|
|
5432
5626
|
const [action] = positionals;
|
|
5433
5627
|
if (action !== "install" && action !== "remove") throw new UsageError("youiyoux agents install|remove [--claude] [--codex] [--json]");
|
|
5434
|
-
const projectRoot =
|
|
5628
|
+
const projectRoot = resolve15(values.project ?? process.cwd());
|
|
5435
5629
|
const repoRoot = await repoRootOf(projectRoot);
|
|
5436
|
-
const target = { project: projectRoot, ...values.config ? { config:
|
|
5630
|
+
const target = { project: projectRoot, ...values.config ? { config: resolve15(values.config) } : {}, ...values.design ? { design: resolve15(values.design) } : {}, ...values.root !== void 0 ? { root: resolve15(values.root || ".") } : {} };
|
|
5437
5631
|
const server = mcpCommand(TOOL_ROOT, target);
|
|
5438
|
-
const system = existsSync5(
|
|
5632
|
+
const system = existsSync5(resolve15(values.config ?? join25(projectRoot, PROJECT_FILE))) ? await project(values) : null;
|
|
5439
5633
|
const claudeServer = system && system.root === repoRoot ? { command: "node", args: mcpArgs(system) } : relativeTo(repoRoot, server);
|
|
5440
5634
|
const both = !values.claude && !values.codex;
|
|
5441
5635
|
const results = [];
|
|
@@ -5506,7 +5700,32 @@ async function startEditor(values, port) {
|
|
|
5506
5700
|
return null;
|
|
5507
5701
|
}
|
|
5508
5702
|
}
|
|
5703
|
+
async function workspaceUi(values) {
|
|
5704
|
+
if (values.design || values.project || values.config || values.root) return null;
|
|
5705
|
+
const { roots, workspace } = await statusTargets(process.cwd());
|
|
5706
|
+
if (workspace === null || roots.length === 0) return null;
|
|
5707
|
+
print(style.dim(`reading the status of ${plural(roots.length, "product")}\u2026`));
|
|
5708
|
+
const report = await workspaceStatus(process.cwd());
|
|
5709
|
+
const first = report.projects.findIndex((p) => !("error" in p));
|
|
5710
|
+
if (first < 0) {
|
|
5711
|
+
print(renderStatus(report));
|
|
5712
|
+
throw new Error("no product in this workspace could be read: see each one's Next above");
|
|
5713
|
+
}
|
|
5714
|
+
const port = values.port ?? DEFAULT_HUB_PORT;
|
|
5715
|
+
let open = null;
|
|
5716
|
+
const hub = await startWorkspaceHub({ roots, current: first, status: () => workspaceStatus(process.cwd()), open: (root) => open ? open(root) : Promise.resolve(1) });
|
|
5717
|
+
print(`${style.ok("workspace hub")} http://localhost:${port}/workspace#key=${hub.key}`);
|
|
5718
|
+
print(style.dim(` ${plural(roots.length, "product")}; showing ${report.projects[first].root} first. Open the link: it carries this run's key, which switching needs`));
|
|
5719
|
+
print(style.dim(" Rules and Changes are read-only here; youiyoux ui --project <dir> opens the rule editor on one product"));
|
|
5720
|
+
try {
|
|
5721
|
+
return await runHub(TOOL_ROOT, { project: roots[first], port, api: hub.url, workspace: (snapshot) => open = snapshot, ...values.inventory ? { inventory: values.inventory } : {}, ...values.detect ? { detect: values.detect } : {} });
|
|
5722
|
+
} finally {
|
|
5723
|
+
await hub.close();
|
|
5724
|
+
}
|
|
5725
|
+
}
|
|
5509
5726
|
async function cmdUi(values) {
|
|
5727
|
+
const workspace = await workspaceUi(values);
|
|
5728
|
+
if (workspace !== null) return workspace;
|
|
5510
5729
|
const port = values.port ?? DEFAULT_HUB_PORT;
|
|
5511
5730
|
const editor = await startEditor(values, port);
|
|
5512
5731
|
try {
|
|
@@ -5518,20 +5737,20 @@ async function cmdUi(values) {
|
|
|
5518
5737
|
async function cmdDetect(values, positionals) {
|
|
5519
5738
|
const target = detectTarget(positionals);
|
|
5520
5739
|
if (!target) throw new UsageError("youiyoux detect <repo-path> or youiyoux detect <url\u2026> [--expose] (one repo, or one or more URLs; not both)");
|
|
5521
|
-
const { repoReport, siteReport, writeReport } = await import("./src-
|
|
5522
|
-
const out =
|
|
5740
|
+
const { repoReport, siteReport, writeReport } = await import("./src-ZG7JU6YJ.js");
|
|
5741
|
+
const out = resolve15(values.out ?? ".youi/detect");
|
|
5523
5742
|
const report = target.kind === "repo" ? await repoReport(target.path) : await siteReport(target.urls, { out, expose: values.expose, ...process.env.YOUI_CHROMIUM ? { executablePath: process.env.YOUI_CHROMIUM } : {} });
|
|
5524
5743
|
const file = await writeReport(report, out);
|
|
5525
5744
|
if (values.json) json3(report);
|
|
5526
5745
|
else {
|
|
5527
|
-
const shown2 =
|
|
5746
|
+
const shown2 = relative11(process.cwd(), file);
|
|
5528
5747
|
print(renderDetect(report, shown2 && !shown2.startsWith("..") ? shown2 : file));
|
|
5529
5748
|
}
|
|
5530
5749
|
return 0;
|
|
5531
5750
|
}
|
|
5532
5751
|
async function cmdRender(values, positionals, io) {
|
|
5533
|
-
const root =
|
|
5534
|
-
const targets = positionals.map((t) => existsSync5(
|
|
5752
|
+
const root = resolve15(values.root ?? values.project ?? process.cwd());
|
|
5753
|
+
const targets = positionals.map((t) => existsSync5(resolve15(t)) ? resolve15(t) : t);
|
|
5535
5754
|
try {
|
|
5536
5755
|
const report = await renderShots(root, targets, { ...values.base ? { base: values.base } : {}, ...process.env.YOUI_CHROMIUM ? { executablePath: process.env.YOUI_CHROMIUM } : {}, ...io.render });
|
|
5537
5756
|
if (values.json) json3({ ...report, next: shotsNext(report, (t) => `run youiyoux render${t ? ` ${t}` : ""} again`) });
|
|
@@ -5545,14 +5764,14 @@ async function cmdRender(values, positionals, io) {
|
|
|
5545
5764
|
}
|
|
5546
5765
|
}
|
|
5547
5766
|
async function product(values) {
|
|
5548
|
-
const project2 = await loadProject(
|
|
5549
|
-
return { project: project2, root: project2?.root ??
|
|
5767
|
+
const project2 = await loadProject(resolve15(values.project ?? process.cwd()), loadOptions(values)).catch(() => null);
|
|
5768
|
+
return { project: project2, root: project2?.root ?? resolve15(values.root ?? values.project ?? process.cwd()) };
|
|
5550
5769
|
}
|
|
5551
5770
|
async function cmdRequests(values, positionals) {
|
|
5552
5771
|
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>";
|
|
5553
5772
|
const [action, id, ...rest] = positionals;
|
|
5554
5773
|
if (rest.length > 0) throw new UsageError(usage);
|
|
5555
|
-
const { RequestStore, requestBrief } = await import("./src-
|
|
5774
|
+
const { RequestStore, requestBrief } = await import("./src-EUVBYTKY.js");
|
|
5556
5775
|
const { project: project2, root } = await product(values);
|
|
5557
5776
|
const store = new RequestStore(root, project2?.config.id ?? basename5(root));
|
|
5558
5777
|
const agent = { kind: "agent", name: "youiyoux CLI" };
|
|
@@ -5584,17 +5803,17 @@ async function cmdScreens(values, positionals, io) {
|
|
|
5584
5803
|
const usage = "youiyoux screens capture --base <url of the app in development> [--route <one route>] [--project dir] [--out <screens dir>] [--storage-state <signed-in session>] [--json] or youiyoux screens login --base <url> [--project dir] [--storage-state <file>]";
|
|
5585
5804
|
if (!["capture", "login"].includes(positionals[0] ?? "") || positionals.length > 1 || !values.base) throw new UsageError(usage);
|
|
5586
5805
|
const { root } = await product(values);
|
|
5587
|
-
if (positionals[0] === "login") return screensLogin(values.base, values["storage-state"] ?
|
|
5588
|
-
const dir =
|
|
5589
|
-
if (!existsSync5(
|
|
5806
|
+
if (positionals[0] === "login") return screensLogin(values.base, values["storage-state"] ? resolve15(values["storage-state"]) : sessionFile(root), io);
|
|
5807
|
+
const dir = resolve15(values.out ?? join25(root, ".youi/screens"));
|
|
5808
|
+
if (!existsSync5(join25(dir, "screens.json"))) {
|
|
5590
5809
|
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":"/"}]}
|
|
5591
5810
|
`);
|
|
5592
5811
|
return 1;
|
|
5593
5812
|
}
|
|
5594
|
-
const session = chosenSession(root, values["storage-state"] ?
|
|
5813
|
+
const session = chosenSession(root, values["storage-state"] ? resolve15(values["storage-state"]) : void 0);
|
|
5595
5814
|
if (session?.saved) process.stderr.write(`${style.dim(`signed in with the session youiyoux screens login saved (${session.file}); delete it to capture signed out`)}
|
|
5596
5815
|
`);
|
|
5597
|
-
const { launchBrowser } = await import("./src-
|
|
5816
|
+
const { launchBrowser } = await import("./src-ZG7JU6YJ.js");
|
|
5598
5817
|
const browser = await launchBrowser(process.env.YOUI_CHROMIUM, { purpose: { what: "youiyoux screens capture", command: "youiyoux screens capture" } });
|
|
5599
5818
|
try {
|
|
5600
5819
|
const report = await captureScreens(dir, { base: values.base, root, browser, ...values.route ? { routes: [values.route] } : {}, ...session ? { storageState: session.file } : {}, log: (line) => process.stderr.write(`${style.dim(line)}
|
|
@@ -5651,7 +5870,7 @@ async function cmdReport(values, positionals, io) {
|
|
|
5651
5870
|
return result.code;
|
|
5652
5871
|
}
|
|
5653
5872
|
async function cmdMcp(values) {
|
|
5654
|
-
const { startStdioServer } = await import("./src-
|
|
5873
|
+
const { startStdioServer } = await import("./src-YKPJ3PII.js");
|
|
5655
5874
|
await startStdioServer({ projectRoot: values.project ?? process.cwd(), ...loadOptions(values), ...values.cache ? { discoverCache: values.cache } : {} });
|
|
5656
5875
|
return -1;
|
|
5657
5876
|
}
|
|
@@ -5662,7 +5881,7 @@ function positiveInt(value, flag) {
|
|
|
5662
5881
|
return n;
|
|
5663
5882
|
}
|
|
5664
5883
|
async function cmdDiscover(values, positionals, io) {
|
|
5665
|
-
const cacheDir =
|
|
5884
|
+
const cacheDir = resolve15(discoverCacheDir(values.cache));
|
|
5666
5885
|
const { path, home } = indexOf(values);
|
|
5667
5886
|
const catalog = () => readCatalog(cacheDir, path);
|
|
5668
5887
|
const [action, ...rest] = positionals;
|
|
@@ -5714,6 +5933,7 @@ ${style.dim(`store \u2192 ${storeLocation({ path })} (${plural(loaded.chosen, "l
|
|
|
5714
5933
|
}
|
|
5715
5934
|
var COMMANDS = {
|
|
5716
5935
|
adopt: cmdAdopt,
|
|
5936
|
+
status: cmdStatus,
|
|
5717
5937
|
system: cmdSystem,
|
|
5718
5938
|
link: cmdLink,
|
|
5719
5939
|
unlink: cmdUnlink,
|