youiyoux 0.1.13 → 0.1.14
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-ZWVWENSB.js → chunk-A2IZOTJG.js} +1 -1
- package/dist/chunks/{chunk-5I2VHSEN.js → chunk-ALQVHSF2.js} +1 -1
- package/dist/chunks/{chunk-EV62TUDV.js → chunk-EN64OSUT.js} +230 -288
- package/dist/chunks/{chunk-DX2NKY2M.js → chunk-F3KCL226.js} +4 -4
- package/dist/chunks/chunk-FTF4MBV5.js +110 -0
- package/dist/chunks/{chunk-PCLXMWZ2.js → chunk-HII2I2PI.js} +3 -3
- package/dist/chunks/{chunk-XOXF2ILO.js → chunk-HIXGUALJ.js} +1 -1
- package/dist/chunks/{chunk-N5Z5A637.js → chunk-JGEVNQ5R.js} +2 -2
- package/dist/chunks/{chunk-PWGZRP3C.js → chunk-MIUG2Z43.js} +180 -8
- package/dist/chunks/{chunk-NF4OJYKC.js → chunk-S7UN5KQK.js} +1 -1
- package/dist/chunks/{chunk-ZOQW6LNH.js → chunk-TPP4HLDB.js} +446 -29
- package/dist/chunks/ingest-OF4Z33L2.js +52 -0
- package/dist/chunks/{src-HVYMF4S2.js → src-3LEBH7E3.js} +7 -7
- package/dist/chunks/{src-IKDQ2BZO.js → src-4BOFDAZD.js} +1 -1
- package/dist/chunks/{src-4QOHR5GC.js → src-6JO73FOS.js} +3 -3
- package/dist/chunks/{src-E6ZPFKPR.js → src-7LETTRRF.js} +23 -3
- package/dist/chunks/{src-PBM76LFQ.js → src-7SHBAJEO.js} +2 -2
- package/dist/chunks/{src-R7JGKOYI.js → src-CCGTRT5J.js} +18 -4
- package/dist/chunks/{src-624TVB6T.js → src-LUPO3O76.js} +2 -2
- package/dist/chunks/{src-YC64NNQ3.js → src-WMGLZKYK.js} +2 -2
- package/dist/hub/assets/{CandidatePanel-DfntneYT.js → CandidatePanel-BbE2xCN2.js} +1 -1
- package/dist/hub/assets/CatalogScreen-CBlaW1-N.js +1 -0
- package/dist/hub/assets/ChangesScreen-WaA9Y7zq.js +1 -0
- package/dist/hub/assets/{CheatSheet-B1dXTYTW.js → CheatSheet-CGfTS7zw.js} +1 -1
- package/dist/hub/assets/{CommandPalette-LBZHJ659.js → CommandPalette-D4WigyuD.js} +1 -1
- package/dist/hub/assets/{DiscoverScreen-Yd3gVUG4.js → DiscoverScreen-CVtcQCM4.js} +2 -2
- package/dist/hub/assets/DraftEditor-Mp1bT8-o.js +5 -0
- package/dist/hub/assets/{GapsScreen-DPYGlNnA.js → GapsScreen-DzB0TfH3.js} +1 -1
- package/dist/hub/assets/{HomeScreen-BCPPk7mz.js → HomeScreen-BVxjYDtc.js} +1 -1
- package/dist/hub/assets/InventoryScreen-D33_YchG.js +1 -0
- package/dist/hub/assets/{LibraryScreen-BVXhOVPU.js → LibraryScreen-B8lAJBGW.js} +1 -1
- package/dist/hub/assets/{Opened-CJyMbxqV.js → Opened-DgNa-hGA.js} +1 -1
- package/dist/hub/assets/{OrgApp-Dxs_7CxZ.js → OrgApp-Q8YNFE-z.js} +1 -1
- package/dist/hub/assets/{Preview-DWFP0BIe.js → Preview-yu3LaZKL.js} +1 -1
- package/dist/hub/assets/{RuleDetail-C2fTlLJL.js → RuleDetail-BqVdc20s.js} +1 -1
- package/dist/hub/assets/{RulesScreen-BABeAGJg.js → RulesScreen-mb3OUlOB.js} +1 -1
- package/dist/hub/assets/{ScreenImage-CyhKm_nj.js → ScreenImage-DUMSgBJL.js} +1 -1
- package/dist/hub/assets/{ScreensScreen-8Ih8byGy.js → ScreensScreen-DjN5mwSP.js} +1 -1
- package/dist/hub/assets/{SearchField-hF-6-YDM.js → SearchField-ByftoJws.js} +1 -1
- package/dist/hub/assets/{Segmented-Dzi1x49S.js → Segmented-CTMaLPgh.js} +1 -1
- package/dist/hub/assets/{ServiceDown-S4ya0Cob.js → ServiceDown-BghtjpTn.js} +1 -1
- package/dist/hub/assets/{SpecimenCapture-e_pgT4Sp.js → SpecimenCapture-CglZ4bn-.js} +1 -1
- package/dist/hub/assets/{Specimens-D_9hjlJH.js → Specimens-D5ehj5-O.js} +2 -2
- package/dist/hub/assets/{StackScreen-J2FQilLW.js → StackScreen-w5hCLj_R.js} +1 -1
- package/dist/hub/assets/{StubScreens-DAkMph3i.js → StubScreens-DfF4aAbp.js} +1 -1
- package/dist/hub/assets/{StyleScreen-C5WytSZU.js → StyleScreen-DKkerxmC.js} +1 -1
- package/dist/hub/assets/{Tabs-DU-fFRDV.js → Tabs-B1IFs-wv.js} +1 -1
- package/dist/hub/assets/TokenDetail-BPTZ9o6J.js +1 -0
- package/dist/hub/assets/TokensScreen-CKnQuVaT.js +1 -0
- package/dist/hub/assets/{WorkspaceScreen-CzZ16fPZ.js → WorkspaceScreen-DwjGW6eY.js} +1 -1
- package/dist/hub/assets/{client-Bdgr12LP.js → client-uMxZXiDl.js} +1 -1
- package/dist/hub/assets/{discover-va2KFuK_.js → discover-Yfb0eB14.js} +1 -1
- package/dist/hub/assets/{dist-CC_p8DIj.js → dist-BvRlRM3Z.js} +1 -1
- package/dist/hub/assets/{dist-C8tf4g8c.js → dist-CL3qgCbi.js} +1 -1
- package/dist/hub/assets/{dist-YTWqg5sS.js → dist-tjVfXRHc.js} +1 -1
- package/dist/hub/assets/{family-tiles-qaK1-_c8.js → family-tiles-dZqjsxro.js} +1 -1
- package/dist/hub/assets/link-2-dzvhLwTC.js +1 -0
- package/dist/hub/assets/main-DNLr0KzQ.css +2 -0
- package/dist/hub/assets/main-Djqho539.js +2 -0
- package/dist/hub/assets/{try-live-Iys3nCBG.js → try-live-Dxsjf62v.js} +1 -1
- package/dist/hub/assets/{workflow-C53UBmRZ.js → workflow-Bv814-L8.js} +1 -1
- package/dist/hub/index.html +2 -2
- package/dist/hub-previews.js +6 -6
- package/dist/hub-server.js +3 -3
- package/dist/hub-snapshot.js +1 -1
- package/dist/schema/youi.library.schema.json +3 -1
- package/dist/youi.js +8 -7
- package/dist/youiyoux.js +8 -7
- package/package.json +4 -4
- package/dist/hub/assets/CatalogScreen-kpFYZqX3.js +0 -1
- package/dist/hub/assets/ChangesScreen-Chu-Ui1B.js +0 -1
- package/dist/hub/assets/DraftEditor-QH9Sa_Uc.js +0 -5
- package/dist/hub/assets/InventoryScreen-SleB733C.js +0 -1
- package/dist/hub/assets/TokenDetail-CDY1xxb9.js +0 -1
- package/dist/hub/assets/TokensScreen-Sx4aICWk.js +0 -1
- package/dist/hub/assets/main-cvOFSjox.js +0 -2
- package/dist/hub/assets/main-pNY4iNRo.css +0 -2
|
@@ -1,4 +1,15 @@
|
|
|
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
|
+
import {
|
|
3
|
+
bar,
|
|
4
|
+
ms,
|
|
5
|
+
padEnd,
|
|
6
|
+
padStart,
|
|
7
|
+
plural,
|
|
8
|
+
rule,
|
|
9
|
+
startRuleEditor,
|
|
10
|
+
style,
|
|
11
|
+
truncate
|
|
12
|
+
} from "./chunk-FTF4MBV5.js";
|
|
2
13
|
import {
|
|
3
14
|
BASELINE_FILE,
|
|
4
15
|
DEFAULT_EXCLUDE,
|
|
@@ -53,7 +64,7 @@ import {
|
|
|
53
64
|
vendoredPath,
|
|
54
65
|
whereUsed,
|
|
55
66
|
withFile
|
|
56
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-HII2I2PI.js";
|
|
57
68
|
import {
|
|
58
69
|
escapingLinks,
|
|
59
70
|
within
|
|
@@ -67,7 +78,7 @@ import {
|
|
|
67
78
|
libraryOfPackage,
|
|
68
79
|
packageOf,
|
|
69
80
|
playwrightCli
|
|
70
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-ALQVHSF2.js";
|
|
71
82
|
import {
|
|
72
83
|
MissingIndexError,
|
|
73
84
|
buildGaps,
|
|
@@ -85,7 +96,7 @@ import {
|
|
|
85
96
|
sharedStore,
|
|
86
97
|
showFromCatalog,
|
|
87
98
|
syncIndex
|
|
88
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-TPP4HLDB.js";
|
|
89
100
|
import {
|
|
90
101
|
checkpointSqlite,
|
|
91
102
|
indexHome,
|
|
@@ -93,7 +104,7 @@ import {
|
|
|
93
104
|
openSqlite,
|
|
94
105
|
projectGraph,
|
|
95
106
|
storeLocation
|
|
96
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-A2IZOTJG.js";
|
|
97
108
|
import {
|
|
98
109
|
DL_EXT,
|
|
99
110
|
buildTokens,
|
|
@@ -103,7 +114,7 @@ import {
|
|
|
103
114
|
parseCssColor,
|
|
104
115
|
parseDimension,
|
|
105
116
|
readRules
|
|
106
|
-
} from "./chunk-
|
|
117
|
+
} from "./chunk-HIXGUALJ.js";
|
|
107
118
|
import {
|
|
108
119
|
Baseline,
|
|
109
120
|
CiRecord,
|
|
@@ -139,11 +150,10 @@ import {
|
|
|
139
150
|
ruleSlug,
|
|
140
151
|
safeId,
|
|
141
152
|
sha256,
|
|
142
|
-
shortHash,
|
|
143
153
|
toPosix,
|
|
144
154
|
unifiedDiff,
|
|
145
155
|
writeFileAtomic
|
|
146
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-S7UN5KQK.js";
|
|
147
157
|
import {
|
|
148
158
|
__toESM
|
|
149
159
|
} from "./chunk-WNTS7ZO4.js";
|
|
@@ -151,10 +161,10 @@ import {
|
|
|
151
161
|
// ../cli/src/main.ts
|
|
152
162
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
153
163
|
import { execFile as execFile6 } from "node:child_process";
|
|
154
|
-
import { existsSync as
|
|
155
|
-
import { homedir as
|
|
164
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
165
|
+
import { homedir as homedir3 } from "node:os";
|
|
156
166
|
import { appendFile as appendFile2, readFile as readFile11, rm as rm7, rmdir as rmdir3 } from "node:fs/promises";
|
|
157
|
-
import { basename as basename5, dirname as dirname13, join as
|
|
167
|
+
import { basename as basename5, dirname as dirname13, join as join27, relative as relative11, resolve as resolve14 } from "node:path";
|
|
158
168
|
import { parseArgs, promisify as promisify6 } from "node:util";
|
|
159
169
|
|
|
160
170
|
// ../cli/src/check.ts
|
|
@@ -1263,13 +1273,11 @@ jobs:
|
|
|
1263
1273
|
ref: ${input.design.commit}
|
|
1264
1274
|
path: .youi-ci/design
|
|
1265
1275
|
token: \${{ secrets.YOUI_REPO_TOKEN }}
|
|
1266
|
-
- uses: pnpm/action-setup@v4
|
|
1267
|
-
with:
|
|
1268
|
-
version: 10.13.1
|
|
1269
1276
|
- uses: actions/setup-node@v4
|
|
1270
1277
|
with:
|
|
1271
1278
|
node-version: 24
|
|
1272
|
-
|
|
1279
|
+
# corepack (in Node 24) runs the pnpm the tool pins: no third-party action beside YOUI_REPO_TOKEN.
|
|
1280
|
+
- run: corepack enable && pnpm install --frozen-lockfile --ignore-scripts
|
|
1273
1281
|
working-directory: .youi-ci/tool
|
|
1274
1282
|
- name: youiyoux check
|
|
1275
1283
|
run: node .youi-ci/tool/packages/cli/bin/youi.js check ${checkArgs}
|
|
@@ -1289,7 +1297,7 @@ async function installWorkflow(project2, toolRoot, target, force, options = {})
|
|
|
1289
1297
|
const projectDir = posix2(relative4(top, await realpath2(project2.root).catch(() => project2.root)));
|
|
1290
1298
|
let text = workflowText({ tool, design, projectDir, configPath, diff });
|
|
1291
1299
|
if (published) {
|
|
1292
|
-
text = text.replace(/ - name: Check out youi\n[\s\S]*?(?= - name: Check out the design)/, "").replace(/ - run: pnpm install --frozen-lockfile --ignore-scripts\n working-directory: .youi-ci\/tool\n/, "").replaceAll("node .youi-ci/tool/packages/cli/bin/youi.js", "npx -y youiyoux");
|
|
1300
|
+
text = text.replace(/ - name: Check out youi\n[\s\S]*?(?= - name: Check out the design)/, "").replace(/ # corepack \(in Node 24\)[^\n]*\n - run: corepack enable && pnpm install --frozen-lockfile --ignore-scripts\n working-directory: .youi-ci\/tool\n/, "").replaceAll("node .youi-ci/tool/packages/cli/bin/youi.js", "npx -y youiyoux");
|
|
1293
1301
|
}
|
|
1294
1302
|
return write(file, text, before, `authoritative: ${published ? "runs the published youiyoux package; pinned to" : `pinned to ${tool.slug}@${tool.commit.slice(0, 7)} and`} rules ${design.slug}@${design.commit.slice(0, 7)}${diff ? "; pull requests also fail on drift they add (youiyoux check --diff --strict)" : ""}`);
|
|
1295
1303
|
}
|
|
@@ -1426,50 +1434,6 @@ async function runRepoCheck(project2, change) {
|
|
|
1426
1434
|
return { identity: null, unmatched: [], failed: [], notRun: [], incomplete: incomplete.length > 0, diff: { base: change.base, commit: change.commit, files: [...change.added.keys()].sort(), findings: findings2, notes, incomplete } };
|
|
1427
1435
|
}
|
|
1428
1436
|
|
|
1429
|
-
// ../cli/src/ui.ts
|
|
1430
|
-
import * as util from "node:util";
|
|
1431
|
-
var styleText2 = util.styleText ?? ((format, text) => [format].flat().reduceRight((inner, name) => {
|
|
1432
|
-
const [open, close] = util.inspect.colors[name] ?? [0, 0];
|
|
1433
|
-
return `\x1B[${open}m${inner}\x1B[${close}m`;
|
|
1434
|
-
}, text));
|
|
1435
|
-
var enabled = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR && process.env.TERM !== "dumb";
|
|
1436
|
-
var paint = (format) => (text) => enabled ? styleText2(format, String(text), { validateStream: false }) : String(text);
|
|
1437
|
-
var style = {
|
|
1438
|
-
bold: paint("bold"),
|
|
1439
|
-
dim: paint("dim"),
|
|
1440
|
-
error: paint("red"),
|
|
1441
|
-
warn: paint("yellow"),
|
|
1442
|
-
ok: paint("green"),
|
|
1443
|
-
live: paint("blue"),
|
|
1444
|
-
accent: paint(["bold", "white"])
|
|
1445
|
-
};
|
|
1446
|
-
function plural(count, word, many = `${word}s`) {
|
|
1447
|
-
return `${count} ${count === 1 ? word : many}`;
|
|
1448
|
-
}
|
|
1449
|
-
var ANSI = /\u001b\[[0-9;]*m/g;
|
|
1450
|
-
function visibleLength(text) {
|
|
1451
|
-
return text.replace(ANSI, "").length;
|
|
1452
|
-
}
|
|
1453
|
-
function padEnd(text, width) {
|
|
1454
|
-
return text + " ".repeat(Math.max(0, width - visibleLength(text)));
|
|
1455
|
-
}
|
|
1456
|
-
function padStart(text, width) {
|
|
1457
|
-
return " ".repeat(Math.max(0, width - visibleLength(text))) + text;
|
|
1458
|
-
}
|
|
1459
|
-
function truncate(text, width) {
|
|
1460
|
-
return text.length <= width ? text : `${text.slice(0, Math.max(0, width - 1))}\u2026`;
|
|
1461
|
-
}
|
|
1462
|
-
function bar(value, max, width = 24) {
|
|
1463
|
-
const cells = max === 0 ? 0 : Math.max(value > 0 ? 1 : 0, Math.round(value / max * width));
|
|
1464
|
-
return style.dim("\u2588".repeat(cells));
|
|
1465
|
-
}
|
|
1466
|
-
function rule(width = 64) {
|
|
1467
|
-
return style.dim("\u2500".repeat(width));
|
|
1468
|
-
}
|
|
1469
|
-
function ms(value) {
|
|
1470
|
-
return value < 1e3 ? `${Math.round(value)} ms` : `${(value / 1e3).toFixed(2)} s`;
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
1437
|
// ../cli/src/render.ts
|
|
1474
1438
|
var SHELL_NOTE = style.dim("app shell: on every screen");
|
|
1475
1439
|
function coverageLine(report) {
|
|
@@ -2145,64 +2109,25 @@ function renderDiscoverShow(result) {
|
|
|
2145
2109
|
].join("\n");
|
|
2146
2110
|
}
|
|
2147
2111
|
|
|
2148
|
-
// ../cli/src/editor.ts
|
|
2149
|
-
import { randomBytes } from "node:crypto";
|
|
2150
|
-
import { existsSync } from "node:fs";
|
|
2151
|
-
import { homedir, userInfo } from "node:os";
|
|
2152
|
-
import { join as join12, resolve as resolve6 } from "node:path";
|
|
2153
|
-
async function swapImpact(candidate, family) {
|
|
2154
|
-
try {
|
|
2155
|
-
const { discoverIndexPath: discoverIndexPath2, sharedStore: sharedStore2 } = await import("./src-E6ZPFKPR.js");
|
|
2156
|
-
const path = discoverIndexPath2();
|
|
2157
|
-
if (!process.env.DATABASE_URL && !existsSync(path)) return null;
|
|
2158
|
-
const impact = await (await sharedStore2(path, process.env, { readOnly: true })).swapImpact(candidate, family);
|
|
2159
|
-
return impact && !("choices" in impact) ? { looks: impact.looks, files: impact.files.length, routes: impact.routes.length, listed: impact.listed } : null;
|
|
2160
|
-
} catch {
|
|
2161
|
-
return null;
|
|
2162
|
-
}
|
|
2163
|
-
}
|
|
2164
|
-
async function libraryLicence(id) {
|
|
2165
|
-
try {
|
|
2166
|
-
const { discoverCacheDir: discoverCacheDir2, findListing } = await import("./src-E6ZPFKPR.js");
|
|
2167
|
-
const { entry } = await findListing(discoverCacheDir2(void 0, process.env), id);
|
|
2168
|
-
return entry.id === id ? entry.license : null;
|
|
2169
|
-
} catch {
|
|
2170
|
-
return null;
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2173
|
-
async function startRuleEditor(options) {
|
|
2174
|
-
const { FileStore, RuleWorkflow, serveWorkflow } = await import("./src-R7JGKOYI.js");
|
|
2175
|
-
const projectRoot = resolve6(options.project);
|
|
2176
|
-
const load2 = { ...options.config ? { configPath: resolve6(options.config) } : {}, ...options.design ? { designRoot: resolve6(options.design) } : {}, ...options.root ? { productRoot: resolve6(options.root) } : {} };
|
|
2177
|
-
const project2 = await loadProject(projectRoot, load2);
|
|
2178
|
-
const stateDir = resolve6(options.state ?? join12(homedir(), ".youi", "workflow", shortHash(`${project2.repo.root}\0${project2.root}`)));
|
|
2179
|
-
const workflow = new RuleWorkflow({ projectRoot, store: new FileStore(stateDir), swapImpact, libraryLicence, ...load2 });
|
|
2180
|
-
const actor = { kind: "person", name: userInfo().username };
|
|
2181
|
-
const info = await workflow.info(actor);
|
|
2182
|
-
const sessionKey = randomBytes(24).toString("base64url");
|
|
2183
|
-
const service = await serveWorkflow({ workflow, actor, sessionKey, port: 0 });
|
|
2184
|
-
return { url: service.url, sessionKey, stateDir, info, close: () => service.close() };
|
|
2185
|
-
}
|
|
2186
|
-
|
|
2187
2112
|
// ../cli/src/hub.ts
|
|
2188
2113
|
import { spawn } from "node:child_process";
|
|
2189
|
-
import { existsSync
|
|
2114
|
+
import { existsSync } from "node:fs";
|
|
2190
2115
|
import { access as access2, mkdtemp as mkdtemp2, rm as rm3 } from "node:fs/promises";
|
|
2191
2116
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
2192
|
-
import { join as
|
|
2117
|
+
import { join as join12, resolve as resolve6 } from "node:path";
|
|
2193
2118
|
var HUB_SNAPSHOT_DIR = ".hub";
|
|
2194
2119
|
var DEFAULT_HUB_PORT = "5173";
|
|
2195
|
-
var named = (options) => ["design", "project", "config", "root", "inventory", "detect"].flatMap((key2) => options[key2] ? [`--${key2}`,
|
|
2120
|
+
var named = (options) => ["design", "project", "config", "root", "inventory", "detect"].flatMap((key2) => options[key2] ? [`--${key2}`, resolve6(options[key2])] : []);
|
|
2196
2121
|
var namesSystem = (options) => ["design", "project", "config", "root"].some((key2) => options[key2]);
|
|
2197
2122
|
function hubPlan(toolRoot, options) {
|
|
2198
|
-
const web =
|
|
2199
|
-
const vite = [
|
|
2123
|
+
const web = join12(toolRoot, "apps/web");
|
|
2124
|
+
const vite = [join12(web, "node_modules/vite/bin/vite.js"), ...options.port ? ["--port", options.port, "--strictPort"] : []];
|
|
2200
2125
|
const watchesDemo = options.watch && !namesSystem(options);
|
|
2201
|
-
const flags = watchesDemo ? [...named(options), "--project",
|
|
2126
|
+
const flags = watchesDemo ? [...named(options), "--project", join12(toolRoot, "examples/demo-app")] : named(options);
|
|
2202
2127
|
const api = options.api ? { YOUI_API: options.api } : {};
|
|
2203
2128
|
if (flags.length === 0) return { web, snapshot: null, env: api, vite, watch: null };
|
|
2204
|
-
const out =
|
|
2205
|
-
const snapshot = [
|
|
2129
|
+
const out = join12(web, HUB_SNAPSHOT_DIR);
|
|
2130
|
+
const snapshot = [join12(web, "scripts/snapshot.ts"), "--out", out, ...flags];
|
|
2206
2131
|
return { web, snapshot, env: { YOUI_HUB_SNAPSHOT: out, ...api }, vite, watch: options.watch ? [...snapshot, "--watch"] : null };
|
|
2207
2132
|
}
|
|
2208
2133
|
var BUILT_HUB = "hub";
|
|
@@ -2210,9 +2135,9 @@ var BUILT_DEMO = "hub-demo";
|
|
|
2210
2135
|
function builtHubPlan(toolRoot, options, out) {
|
|
2211
2136
|
const flags = named(options);
|
|
2212
2137
|
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)");
|
|
2213
|
-
const hub =
|
|
2214
|
-
const snapshot = flags.length > 0 ? [
|
|
2215
|
-
const server = [
|
|
2138
|
+
const hub = join12(toolRoot, BUILT_HUB);
|
|
2139
|
+
const snapshot = flags.length > 0 ? [join12(toolRoot, "hub-snapshot.js"), "--out", out, ...flags] : null;
|
|
2140
|
+
const server = [join12(toolRoot, "hub-server.js"), "--dist", hub, "--kit", join12(hub, "kit"), "--snapshot", snapshot ? out : join12(toolRoot, BUILT_DEMO), ...snapshot ? ["--build-frame"] : [], ...options.port ? ["--port", options.port] : [], ...options.api ? ["--api", options.api] : [], ...options.watch || options.workspace ? ["--live"] : []];
|
|
2216
2141
|
return { snapshot, server, watch: options.watch && snapshot ? [...snapshot, "--watch"] : null };
|
|
2217
2142
|
}
|
|
2218
2143
|
function run5(args, cwd, env, started) {
|
|
@@ -2224,7 +2149,7 @@ function run5(args, cwd, env, started) {
|
|
|
2224
2149
|
});
|
|
2225
2150
|
}
|
|
2226
2151
|
async function runBuiltHub(toolRoot, options) {
|
|
2227
|
-
const out = await mkdtemp2(
|
|
2152
|
+
const out = await mkdtemp2(join12(tmpdir2(), "youiyoux-hub-"));
|
|
2228
2153
|
const children = /* @__PURE__ */ new Set();
|
|
2229
2154
|
const stop = () => {
|
|
2230
2155
|
for (const child of children) child.kill("SIGTERM");
|
|
@@ -2248,7 +2173,7 @@ async function runBuiltHub(toolRoot, options) {
|
|
|
2248
2173
|
}
|
|
2249
2174
|
}
|
|
2250
2175
|
async function runHub(toolRoot, options) {
|
|
2251
|
-
if (
|
|
2176
|
+
if (existsSync(join12(toolRoot, BUILT_HUB, "index.html"))) return runBuiltHub(toolRoot, options);
|
|
2252
2177
|
const plan = hubPlan(toolRoot, options);
|
|
2253
2178
|
await access2(plan.vite[0]).catch(() => {
|
|
2254
2179
|
throw new Error(`the hub's dependencies are not installed: run \`pnpm install\` in ${toolRoot}`);
|
|
@@ -2266,19 +2191,19 @@ async function runHub(toolRoot, options) {
|
|
|
2266
2191
|
}
|
|
2267
2192
|
}
|
|
2268
2193
|
function previewsPlan(toolRoot, options) {
|
|
2269
|
-
const web =
|
|
2194
|
+
const web = join12(toolRoot, "apps/web");
|
|
2270
2195
|
const registry = options.registry ?? "@shadcn";
|
|
2271
|
-
const args = [
|
|
2196
|
+
const args = [join12(web, "scripts/capture-discover-thumbs.ts"), "--hub", `http://localhost:${options.port ?? DEFAULT_HUB_PORT}`];
|
|
2272
2197
|
if (registry !== "all") args.push("--registry", registry);
|
|
2273
2198
|
for (const key2 of ["role", "limit"]) if (options[key2]) args.push(`--${key2}`, options[key2]);
|
|
2274
|
-
if (options.cache) args.push("--cache",
|
|
2199
|
+
if (options.cache) args.push("--cache", resolve6(options.cache));
|
|
2275
2200
|
if (options.force) args.push("--force");
|
|
2276
2201
|
return { web, args };
|
|
2277
2202
|
}
|
|
2278
2203
|
async function runPreviews(toolRoot, options) {
|
|
2279
2204
|
const plan = previewsPlan(toolRoot, options);
|
|
2280
|
-
if (
|
|
2281
|
-
await access2(
|
|
2205
|
+
if (existsSync(join12(toolRoot, BUILT_HUB, "index.html"))) return run5([join12(toolRoot, "hub-previews.js"), ...plan.args.slice(1)], process.cwd(), {});
|
|
2206
|
+
await access2(join12(plan.web, "node_modules/playwright-core")).catch(() => {
|
|
2282
2207
|
throw new Error(`the hub's dependencies are not installed: run \`pnpm install\` in ${toolRoot}`);
|
|
2283
2208
|
});
|
|
2284
2209
|
return run5(plan.args, plan.web, {});
|
|
@@ -2307,7 +2232,7 @@ function renderRequests(briefs, status, unreadable) {
|
|
|
2307
2232
|
|
|
2308
2233
|
// ../cli/src/adopt.ts
|
|
2309
2234
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
2310
|
-
import { basename as basename2, dirname as dirname7, isAbsolute as isAbsolute5, join as
|
|
2235
|
+
import { basename as basename2, dirname as dirname7, isAbsolute as isAbsolute5, join as join13, posix as posix3, relative as relative6, resolve as resolve7 } from "node:path";
|
|
2311
2236
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
2312
2237
|
var OUT_DIR = "design/build";
|
|
2313
2238
|
var DARK_BLOCKS = [
|
|
@@ -2327,7 +2252,7 @@ function slugOf(name) {
|
|
|
2327
2252
|
}
|
|
2328
2253
|
function inside2(root, path, what) {
|
|
2329
2254
|
const normal = posix3.normalize(path.split("\\").join("/")).replace(/^\.\//, "").replace(/\/+$/, "");
|
|
2330
|
-
if (isAbsolute5(normal) || normal === ".." || normal.startsWith("../") || !within(root,
|
|
2255
|
+
if (isAbsolute5(normal) || normal === ".." || normal.startsWith("../") || !within(root, resolve7(root, normal))) throw new Error(`${what} ${JSON.stringify(path)} leads outside ${root}: adopt reads and writes only inside the product`);
|
|
2331
2256
|
return normal;
|
|
2332
2257
|
}
|
|
2333
2258
|
function exportedNames(source) {
|
|
@@ -2366,7 +2291,7 @@ async function stylesheetOf(root, asked, fork) {
|
|
|
2366
2291
|
const generated = [];
|
|
2367
2292
|
let forked = null;
|
|
2368
2293
|
const usable = async (file) => {
|
|
2369
|
-
const css = await readTextOrNull(
|
|
2294
|
+
const css = await readTextOrNull(join13(root, file));
|
|
2370
2295
|
if (css === null) return false;
|
|
2371
2296
|
const made = generatedOf(file, css);
|
|
2372
2297
|
if (made && !generated.some((g) => g.file === file)) generated.push(made);
|
|
@@ -2377,11 +2302,11 @@ async function stylesheetOf(root, asked, fork) {
|
|
|
2377
2302
|
if (!await usable(asked) && generated.length > 0) throw new Error(`${asked} is generated by youiyoux sync${generated[0].system ? ` from ${generated[0].system}` : ""}: name the stylesheet the product writes its own variables in, or take that System's values as the product's own with youiyoux adopt --fork`);
|
|
2378
2303
|
return { file: asked, generated, forked };
|
|
2379
2304
|
}
|
|
2380
|
-
const shadcn = (await readJson(
|
|
2305
|
+
const shadcn = (await readJson(join13(root, "components.json")))?.tailwind?.css;
|
|
2381
2306
|
if (typeof shadcn === "string" && await usable(shadcn)) return { file: posix3.normalize(shadcn), generated, forked };
|
|
2382
2307
|
let best = null;
|
|
2383
2308
|
for (const file of await findFiles(root, ["**/*.css"], ["**/build/**", "**/out/**", "**/.next/**", `${OUT_DIR}/**`])) {
|
|
2384
|
-
const css = await readTextOrNull(
|
|
2309
|
+
const css = await readTextOrNull(join13(root, file)) ?? "";
|
|
2385
2310
|
const count = rootVariables(css).length;
|
|
2386
2311
|
if (count === 0) continue;
|
|
2387
2312
|
const made = generatedOf(file, css);
|
|
@@ -2455,7 +2380,7 @@ ${content}`;
|
|
|
2455
2380
|
}
|
|
2456
2381
|
async function planAdoption(options) {
|
|
2457
2382
|
const root = options.root;
|
|
2458
|
-
const pkg = await readJson(
|
|
2383
|
+
const pkg = await readJson(join13(root, "package.json"));
|
|
2459
2384
|
const name = typeof pkg?.name === "string" ? pkg.name : basename2(root);
|
|
2460
2385
|
const id = options.system ?? slugOf(name);
|
|
2461
2386
|
if (!/^[a-z][a-z0-9-]*$/.test(id)) throw new Error(`"${id}" cannot be a system id: use lowercase letters, digits and hyphens, starting with a letter (--system <id>)`);
|
|
@@ -2463,7 +2388,7 @@ async function planAdoption(options) {
|
|
|
2463
2388
|
const facts = await collectComponents(root);
|
|
2464
2389
|
const chosen = options.componentsDir ?? facts.shadcnUi ?? await uiFolder(root) ?? facts.componentsDir;
|
|
2465
2390
|
const componentsDir = chosen ? inside2(root, chosen, "the components folder") : null;
|
|
2466
|
-
if (!componentsDir || !await exists(
|
|
2391
|
+
if (!componentsDir || !await exists(join13(root, componentsDir))) throw new Error("no folder of components found: pass --components <dir> (the folder your app imports its UI components from)");
|
|
2467
2392
|
const inDir = (file) => posix3.dirname(file) === componentsDir;
|
|
2468
2393
|
const files = (await findFiles(root, [`${componentsDir}/*.{ts,tsx,js,jsx}`])).filter((f) => !/^index\./.test(posix3.basename(f)) && !/\.(test|spec|stories|d)\.[^.]+$/.test(f));
|
|
2469
2394
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -2474,7 +2399,7 @@ async function planAdoption(options) {
|
|
|
2474
2399
|
const RULES = ["color.no-raw-color", "tokens.no-arbitrary-values", "components.canonical-import"].map((r) => `youi:${id}/rule/${r}`);
|
|
2475
2400
|
for (const file of files) {
|
|
2476
2401
|
const defined = (byFile.get(file) ?? []).filter((c) => /^[A-Z]/.test(c.export));
|
|
2477
|
-
const source = await readFile4(
|
|
2402
|
+
const source = await readFile4(join13(root, file), "utf8");
|
|
2478
2403
|
if (defined.length === 0) {
|
|
2479
2404
|
support.push(posix3.basename(file));
|
|
2480
2405
|
continue;
|
|
@@ -2511,7 +2436,7 @@ async function planAdoption(options) {
|
|
|
2511
2436
|
if (components.length === 0) throw new Error(`${componentsDir} exports no React components: pass --components <dir> (the folder your app imports its UI components from)`);
|
|
2512
2437
|
const found = await stylesheetOf(root, options.css, options.fork === true);
|
|
2513
2438
|
const stylesheet = found.file ? inside2(root, found.file, "the stylesheet") : null;
|
|
2514
|
-
const css = stylesheet ? await readTextOrNull(
|
|
2439
|
+
const css = stylesheet ? await readTextOrNull(join13(root, stylesheet)) : null;
|
|
2515
2440
|
if (stylesheet && css === null) throw new Error(`${stylesheet} does not exist (--css <file>: the stylesheet that defines your :root variables)`);
|
|
2516
2441
|
const darkBlocks = css ? DARK_BLOCKS.filter((b) => readRules(css).some((r) => r.preludes.at(-1) === b.selector && (b.outer ? r.preludes.length === 2 && r.preludes[0] === b.outer : r.preludes.length === 1) && r.declarations.some((d) => d.property.startsWith("--")))) : [];
|
|
2517
2442
|
const darkBlock = darkBlocks[0];
|
|
@@ -2542,7 +2467,7 @@ async function planAdoption(options) {
|
|
|
2542
2467
|
if (!stylesheet) notes.push("no stylesheet defines :root variables, so the System has no tokens yet: add them to design/tokens");
|
|
2543
2468
|
const left = (imported?.report.unparsed ?? []).map((l) => ({ ...l, name: full(l.name) }));
|
|
2544
2469
|
const moved = new Set(imported ? variableNames(imported.base).map(full) : []);
|
|
2545
|
-
const importPath = stylesheet ? relative6(dirname7(
|
|
2470
|
+
const importPath = stylesheet ? relative6(dirname7(join13(root, stylesheet)), join13(root, OUT_DIR, "tokens.css")).split("\\").join("/") : "";
|
|
2546
2471
|
const moving = css && moved.size > 0 ? moveDeclarations(css, [{ selector: ":root" }, ...darkBlocks], moved, importPath.startsWith(".") ? importPath : `./${importPath}`) : null;
|
|
2547
2472
|
const rewritten = moving && found.forked ? { ...moving, content: moving.content.split("\n").filter((line) => !line.includes(GENERATED_MARK) && !/^\/\* Built with Terrazzo/.test(line)).join("\n") } : moving;
|
|
2548
2473
|
if (found.forked) notes.push(`forked from ${found.forked.system ?? "the System"}${found.forked.version ? ` v${found.forked.version}` : ""}: this product's System starts from the ${found.forked.count} variables it generated into ${found.forked.file}, and the product no longer follows ${found.forked.system ?? "it"}`);
|
|
@@ -2631,7 +2556,7 @@ function starterRules(id, componentsDir) {
|
|
|
2631
2556
|
|
|
2632
2557
|
// ../cli/src/extract.ts
|
|
2633
2558
|
import { cp, mkdir as mkdir3, mkdtemp as mkdtemp3, readdir as readdir3, readFile as readFile5, realpath as realpath4, rename, rm as rm4, rmdir as rmdir2, stat } from "node:fs/promises";
|
|
2634
|
-
import { basename as basename3, dirname as dirname8, join as
|
|
2559
|
+
import { basename as basename3, dirname as dirname8, join as join14, posix as posix4, relative as relative7, resolve as resolve8, sep as sep2 } from "node:path";
|
|
2635
2560
|
var json2 = (value) => `${JSON.stringify(value, null, 2)}
|
|
2636
2561
|
`;
|
|
2637
2562
|
var toPosix2 = (path) => path.split(sep2).join("/");
|
|
@@ -2646,7 +2571,7 @@ function ownedPaths(project2, paths, kept) {
|
|
|
2646
2571
|
const root = project2.repo.root;
|
|
2647
2572
|
for (const path of paths) {
|
|
2648
2573
|
const own = normalizeRelPath(path);
|
|
2649
|
-
if (own === "." || own.startsWith("../") || !within(root,
|
|
2574
|
+
if (own === "." || own.startsWith("../") || !within(root, join14(root, own)) || resolve8(root, own) === resolve8(root)) throw new Error(`the System's ${path} is not a folder of its own inside ${root}: move its files into one (design/\u2026) before extracting; nothing was changed`);
|
|
2650
2575
|
for (const keep of kept.map((k) => normalizeRelPath(toPosix2(k)))) {
|
|
2651
2576
|
if (keep === own || keep.startsWith(`${own}/`)) throw new Error(`the System's ${own} holds ${keep}, which stays in the product: move the System's files into a folder of their own before extracting; nothing was changed`);
|
|
2652
2577
|
}
|
|
@@ -2654,27 +2579,27 @@ function ownedPaths(project2, paths, kept) {
|
|
|
2654
2579
|
}
|
|
2655
2580
|
async function extractSystem(project2, dir, options = {}) {
|
|
2656
2581
|
if (!await heldInPlace(project2)) throw new Error(`${project2.root}'s System is already a design repo of its own (${project2.repo.root}): extract moves a System youiyoux adopt keeps inside the product`);
|
|
2657
|
-
const target =
|
|
2582
|
+
const target = resolve8(dir);
|
|
2658
2583
|
if (await isDirectory(target)) {
|
|
2659
2584
|
if ((await readdir3(target)).length > 0) throw new Error(`${target} already exists and is not empty: extract into a new folder`);
|
|
2660
2585
|
} else if (await stat(target).catch(() => null) !== null) throw new Error(`${target} already exists: extract into a new folder`);
|
|
2661
2586
|
const { repo, system } = project2;
|
|
2662
2587
|
const config = system.config;
|
|
2663
|
-
const from = (path) =>
|
|
2588
|
+
const from = (path) => join14(repo.root, path);
|
|
2664
2589
|
const components = from(config.components);
|
|
2665
2590
|
const implementations = from(implementationsDir(config));
|
|
2666
2591
|
const tokensDir = posix4.dirname(config.tokens);
|
|
2667
2592
|
const removed = [DESIGN_CONFIG_FILE, config.components, tokensDir, config.rules, ...config.design ? [config.design] : []];
|
|
2668
|
-
ownedPaths(project2, removed, [implementationsDir(config), relative7(project2.root, project2.configFile ??
|
|
2593
|
+
ownedPaths(project2, removed, [implementationsDir(config), relative7(project2.root, project2.configFile ?? join14(project2.root, PROJECT_FILE)), project2.config.outputs.dir, relative7(project2.root, target)]);
|
|
2669
2594
|
const { implementations: _inPlace, ...rest } = config;
|
|
2670
2595
|
const shared = config.support.map((file) => `_shared/${posix4.basename(file)}`);
|
|
2671
2596
|
const next2 = { ...rest, tokens: `tokens/${posix4.relative(tokensDir, config.tokens)}`, components: "components", support: shared, rules: "rules", ...config.design ? { design: "design.md" } : {} };
|
|
2672
2597
|
const written = [];
|
|
2673
|
-
const temp = await mkdtemp3(
|
|
2598
|
+
const temp = await mkdtemp3(join14(dirname8(target), `.${basename3(target)}.`));
|
|
2674
2599
|
try {
|
|
2675
2600
|
const copy = async (source2, to) => {
|
|
2676
|
-
await mkdir3(dirname8(
|
|
2677
|
-
await cp(source2,
|
|
2601
|
+
await mkdir3(dirname8(join14(temp, to)), { recursive: true });
|
|
2602
|
+
await cp(source2, join14(temp, to), { recursive: true });
|
|
2678
2603
|
};
|
|
2679
2604
|
await copy(components, "components");
|
|
2680
2605
|
const placed = /* @__PURE__ */ new Map();
|
|
@@ -2683,31 +2608,31 @@ async function extractSystem(project2, dir, options = {}) {
|
|
|
2683
2608
|
const at = toPosix2(relative7(components, folder));
|
|
2684
2609
|
const file = placed.get(contract.source.file) ?? `${at}/${posix4.basename(contract.source.file)}`;
|
|
2685
2610
|
if (!placed.has(contract.source.file)) {
|
|
2686
|
-
await copy(
|
|
2611
|
+
await copy(join14(implementations, contract.source.file), `components/${file}`);
|
|
2687
2612
|
placed.set(contract.source.file, file);
|
|
2688
2613
|
}
|
|
2689
|
-
const raw = JSON.parse(await readFile5(
|
|
2690
|
-
await writeFileAtomic(
|
|
2614
|
+
const raw = JSON.parse(await readFile5(join14(folder, contractFile), "utf8"));
|
|
2615
|
+
await writeFileAtomic(join14(temp, "components", at, contractFile), json2({ ...raw, source: { ...raw.source, file } }));
|
|
2691
2616
|
}
|
|
2692
|
-
for (const [i, file] of config.support.entries()) await copy(
|
|
2617
|
+
for (const [i, file] of config.support.entries()) await copy(join14(implementations, file), `components/${shared[i]}`);
|
|
2693
2618
|
await copy(from(tokensDir), "tokens");
|
|
2694
2619
|
if (await isDirectory(from(config.rules))) await copy(from(config.rules), "rules");
|
|
2695
2620
|
if (config.design) await copy(from(config.design), "design.md");
|
|
2696
|
-
await writeFileAtomic(
|
|
2697
|
-
if (options.package) await writeFileAtomic(
|
|
2621
|
+
await writeFileAtomic(join14(temp, DESIGN_CONFIG_FILE), json2({ schema: "youi.config/v1", name: repo.config.name, systems: [next2] }));
|
|
2622
|
+
if (options.package) await writeFileAtomic(join14(temp, "package.json"), json2({ name: options.package, version: config.version, description: config.description, files: [DESIGN_CONFIG_FILE, "components", "tokens", "rules", ...config.design ? ["design.md"] : []] }));
|
|
2698
2623
|
const leaving = escapingLinks(temp);
|
|
2699
2624
|
if (leaving.length > 0) throw new Error(`the System has links that lead outside it (${leaving.slice(0, 3).join(", ")}); nothing was changed`);
|
|
2700
2625
|
await loadDesignRepo(temp);
|
|
2701
|
-
for (const entry of await readdir3(temp, { recursive: true })) if (!await isDirectory(
|
|
2626
|
+
for (const entry of await readdir3(temp, { recursive: true })) if (!await isDirectory(join14(temp, entry))) written.push(toPosix2(entry));
|
|
2702
2627
|
written.sort();
|
|
2703
2628
|
const source = { path: toPosix2(relative7(project2.root, target)) || "." };
|
|
2704
2629
|
if (!options.dryRun) {
|
|
2705
2630
|
if (await isDirectory(target)) await rmdir2(target);
|
|
2706
2631
|
await rename(temp, target);
|
|
2707
|
-
const configFile = project2.configFile ??
|
|
2632
|
+
const configFile = project2.configFile ?? join14(project2.root, PROJECT_FILE);
|
|
2708
2633
|
const raw = JSON.parse(await readTextOrNull(configFile) ?? "{}");
|
|
2709
2634
|
await writeFileAtomic(configFile, json2({ ...raw, source }));
|
|
2710
|
-
for (const path of removed) await rm4(
|
|
2635
|
+
for (const path of removed) await rm4(join14(repo.root, path), { recursive: true, force: true });
|
|
2711
2636
|
}
|
|
2712
2637
|
return { target, system: next2, written, removed, source };
|
|
2713
2638
|
} finally {
|
|
@@ -2717,7 +2642,7 @@ async function extractSystem(project2, dir, options = {}) {
|
|
|
2717
2642
|
|
|
2718
2643
|
// ../cli/src/upgrade.ts
|
|
2719
2644
|
import { lstat as lstat2, rm as rm5 } from "node:fs/promises";
|
|
2720
|
-
import { join as
|
|
2645
|
+
import { join as join15 } from "node:path";
|
|
2721
2646
|
var LOCK_FILE2 = "youi.lock.json";
|
|
2722
2647
|
var WRITES = /* @__PURE__ */ new Set(["created", "updated", "merged", "adopted", "removed"]);
|
|
2723
2648
|
function compareVersions(a, b) {
|
|
@@ -2772,7 +2697,7 @@ var Snapshot = class {
|
|
|
2772
2697
|
this.root = root;
|
|
2773
2698
|
}
|
|
2774
2699
|
async keep(files) {
|
|
2775
|
-
for (const file of files) if (!this.saved.has(file)) this.saved.set(file, await readTextOrNull(
|
|
2700
|
+
for (const file of files) if (!this.saved.has(file)) this.saved.set(file, await readTextOrNull(join15(this.root, file)));
|
|
2776
2701
|
}
|
|
2777
2702
|
/** A file's content before a step wrote it, unless it was kept already. */
|
|
2778
2703
|
remember(file, content) {
|
|
@@ -2782,7 +2707,7 @@ var Snapshot = class {
|
|
|
2782
2707
|
async restore() {
|
|
2783
2708
|
const stuck = [];
|
|
2784
2709
|
for (const [file, content] of this.saved) {
|
|
2785
|
-
const path =
|
|
2710
|
+
const path = join15(this.root, file);
|
|
2786
2711
|
try {
|
|
2787
2712
|
if (content !== null) {
|
|
2788
2713
|
if (await readTextOrNull(path) !== content) await writeFileAtomic(path, content);
|
|
@@ -2831,7 +2756,7 @@ async function upgradeProject(project2, options = {}) {
|
|
|
2831
2756
|
const changes = sync.some((a) => WRITES.has(a.action)) || previews.some((m) => m.status !== "noop") || ref !== null || lock.systemVersion !== to.version;
|
|
2832
2757
|
if (!changes) return result("current", { sync, migrations: previews }, "nothing to do");
|
|
2833
2758
|
if (!options.write) return result("preview", { sync, migrations: previews }, `youiyoux upgrade${options.to !== void 0 ? ` --to ${options.to}` : ""} --write`);
|
|
2834
|
-
const configFile = project2.configFile ??
|
|
2759
|
+
const configFile = project2.configFile ?? join15(project2.root, PROJECT_FILE);
|
|
2835
2760
|
const snapshot = new Snapshot(project2.root);
|
|
2836
2761
|
const configBefore = await readTextOrNull(configFile);
|
|
2837
2762
|
await snapshot.keep([LOCK_FILE2, ...dry.contents.keys(), ...dry.actions.filter((a) => a.action === "removed").map((a) => a.file), ...previews.flatMap((m) => m.changes.map((c) => c.file))]);
|
|
@@ -2890,14 +2815,14 @@ function renderUpgrade(r, showDiff) {
|
|
|
2890
2815
|
// ../cli/src/record.ts
|
|
2891
2816
|
import { execFile as execFile5 } from "node:child_process";
|
|
2892
2817
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
2893
|
-
import { join as
|
|
2818
|
+
import { join as join19 } from "node:path";
|
|
2894
2819
|
import { promisify as promisify5 } from "node:util";
|
|
2895
2820
|
|
|
2896
2821
|
// ../cli/src/org-hub.ts
|
|
2897
2822
|
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
|
|
2898
2823
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
2899
2824
|
import { createServer } from "node:http";
|
|
2900
|
-
import { extname, join as
|
|
2825
|
+
import { extname, join as join16, normalize, sep as sep3 } from "node:path";
|
|
2901
2826
|
|
|
2902
2827
|
// ../cli/src/github-oidc.ts
|
|
2903
2828
|
import { createPublicKey, verify } from "node:crypto";
|
|
@@ -3088,7 +3013,7 @@ async function startOrgHub(options) {
|
|
|
3088
3013
|
const secure = options.secureCookies ?? !local;
|
|
3089
3014
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
3090
3015
|
const session = createHmac("sha256", options.viewKey).update("youiyoux hub viewer").digest("base64url");
|
|
3091
|
-
const page = options.dist ? (await readFile6(
|
|
3016
|
+
const page = options.dist ? (await readFile6(join16(options.dist, "index.html"), "utf8")).replace("</head>", ` <meta name="${ORG_META}" content="/api/org" />
|
|
3092
3017
|
</head>`) : null;
|
|
3093
3018
|
const pagePolicy = csp(page ? [...page.matchAll(/<script>([\s\S]*?)<\/script>/g)].map((m) => m[1]) : []);
|
|
3094
3019
|
const viewer = (req) => {
|
|
@@ -3098,9 +3023,9 @@ async function startOrgHub(options) {
|
|
|
3098
3023
|
};
|
|
3099
3024
|
const cookieHeader = (value, maxAge) => `${COOKIE}=${value}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${maxAge}${secure ? "; Secure" : ""}`;
|
|
3100
3025
|
const serveFile = async (res, path) => {
|
|
3101
|
-
const root =
|
|
3102
|
-
const file = normalize(
|
|
3103
|
-
if (!(file.startsWith(`${root}${sep3}`) || file ===
|
|
3026
|
+
const root = join16(options.dist, "assets");
|
|
3027
|
+
const file = normalize(join16(options.dist, path));
|
|
3028
|
+
if (!(file.startsWith(`${root}${sep3}`) || file === join16(options.dist, "favicon.svg"))) return send(res, 404, { error: "not found" });
|
|
3104
3029
|
const body = await readFile6(file).catch(() => null);
|
|
3105
3030
|
if (!body) return send(res, 404, { error: "not found" });
|
|
3106
3031
|
res.writeHead(200, { ...HEADERS, "Content-Type": TYPES[extname(file)] ?? "application/octet-stream", "Cache-Control": path.startsWith("/assets/") ? "public, max-age=31536000, immutable" : "no-cache" });
|
|
@@ -3190,8 +3115,8 @@ async function startOrgHub(options) {
|
|
|
3190
3115
|
// ../cli/src/report/safe.ts
|
|
3191
3116
|
import { realpathSync } from "node:fs";
|
|
3192
3117
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
3193
|
-
import { homedir
|
|
3194
|
-
import { join as
|
|
3118
|
+
import { homedir, userInfo } from "node:os";
|
|
3119
|
+
import { join as join17 } from "node:path";
|
|
3195
3120
|
|
|
3196
3121
|
// ../cli/src/report/filters.ts
|
|
3197
3122
|
var SHOWCASE_GLOBS = ["**/{__stories__,.storybook,storybook,storybook-static,example,examples,demo,demos,playground,showcase,showcases}/**", "**/*.stories.*", "**/*.story.*"];
|
|
@@ -3328,7 +3253,7 @@ async function dotenvValues(root) {
|
|
|
3328
3253
|
const files = await findFiles(root, [".env", ".env.*", "**/.env", "**/.env.*"]).catch(() => []);
|
|
3329
3254
|
const values = [];
|
|
3330
3255
|
for (const file of files) {
|
|
3331
|
-
const text = await readFile7(
|
|
3256
|
+
const text = await readFile7(join17(root, file), "utf8").catch(() => "");
|
|
3332
3257
|
for (const line of text.split(/\r?\n/)) {
|
|
3333
3258
|
const match = /^\s*(?:export\s+)?[A-Za-z_][A-Za-z0-9_.-]*\s*=\s*(.*)$/.exec(line);
|
|
3334
3259
|
if (!match) continue;
|
|
@@ -3367,10 +3292,10 @@ var Redactor = class _Redactor {
|
|
|
3367
3292
|
}
|
|
3368
3293
|
};
|
|
3369
3294
|
this.roots = [.../* @__PURE__ */ new Set([options.root, real(options.root)])].sort((a, b) => b.length - a.length);
|
|
3370
|
-
this.home = options.home ??
|
|
3295
|
+
this.home = options.home ?? homedir();
|
|
3371
3296
|
this.username = options.username ?? (() => {
|
|
3372
3297
|
try {
|
|
3373
|
-
return
|
|
3298
|
+
return userInfo().username;
|
|
3374
3299
|
} catch {
|
|
3375
3300
|
return "";
|
|
3376
3301
|
}
|
|
@@ -3447,10 +3372,10 @@ var Redactor = class _Redactor {
|
|
|
3447
3372
|
|
|
3448
3373
|
// ../cli/src/status.ts
|
|
3449
3374
|
import { realpath as realpath5 } from "node:fs/promises";
|
|
3450
|
-
import { dirname as dirname9, join as
|
|
3375
|
+
import { dirname as dirname9, join as join18, relative as relative8, resolve as resolve9 } from "node:path";
|
|
3451
3376
|
var placeOf = (cwd, root) => {
|
|
3452
3377
|
const rel = relative8(cwd, root) || ".";
|
|
3453
|
-
return rel.split(/[\\/]/).filter((part) => part === "..").length > 1 ?
|
|
3378
|
+
return rel.split(/[\\/]/).filter((part) => part === "..").length > 1 ? resolve9(root) : rel;
|
|
3454
3379
|
};
|
|
3455
3380
|
var WRITES2 = /* @__PURE__ */ new Set(["created", "updated", "merged", "adopted", "conflict", "removed"]);
|
|
3456
3381
|
function sourceOf(project2) {
|
|
@@ -3458,7 +3383,7 @@ function sourceOf(project2) {
|
|
|
3458
3383
|
const source = project2.config.source;
|
|
3459
3384
|
if ("package" in source) return `package ${source.package}`;
|
|
3460
3385
|
if ("git" in source) return `git ${source.git} at ${source.ref}`;
|
|
3461
|
-
return
|
|
3386
|
+
return resolve9(project2.root) === resolve9(project2.repo.root) ? "this repo" : `path ${source.path}`;
|
|
3462
3387
|
}
|
|
3463
3388
|
function nextStep(s, migrations) {
|
|
3464
3389
|
if (s.sync.state === "never") return "youiyoux sync: this product has never been synced with its System";
|
|
@@ -3480,7 +3405,7 @@ async function projectStatus(project2, cwd = process.cwd()) {
|
|
|
3480
3405
|
const comparison = check.baseline?.comparison;
|
|
3481
3406
|
const counted = comparison ? [...comparison.new, ...comparison.regressed] : check.violations;
|
|
3482
3407
|
const usages = check.scan.report.usages;
|
|
3483
|
-
const { RequestStore } = await import("./src-
|
|
3408
|
+
const { RequestStore } = await import("./src-CCGTRT5J.js");
|
|
3484
3409
|
const requests = await new RequestStore(project2.root, project2.config.id).list();
|
|
3485
3410
|
const status = {
|
|
3486
3411
|
id: project2.config.id,
|
|
@@ -3501,21 +3426,21 @@ async function projectStatus(project2, cwd = process.cwd()) {
|
|
|
3501
3426
|
return { ...status, next: nextStep(status, lock ? pendingMigrations(project2, lock).length : 0) };
|
|
3502
3427
|
}
|
|
3503
3428
|
async function statusTargets(cwd, named2) {
|
|
3504
|
-
if (named2) return { roots: [
|
|
3429
|
+
if (named2) return { roots: [resolve9(named2)], workspace: null };
|
|
3505
3430
|
const product2 = findUp(cwd, PROJECT_FILE);
|
|
3506
3431
|
if (product2) return { roots: [product2], workspace: null };
|
|
3507
3432
|
const at = findUp(cwd, WORKSPACE_FILE);
|
|
3508
3433
|
if (at) {
|
|
3509
|
-
const file =
|
|
3434
|
+
const file = join18(at, WORKSPACE_FILE);
|
|
3510
3435
|
const workspace = await readDefinition(file, WorkspaceConfig);
|
|
3511
|
-
return { roots: workspace.projects.map((p) =>
|
|
3436
|
+
return { roots: workspace.projects.map((p) => resolve9(at, p)), workspace: file };
|
|
3512
3437
|
}
|
|
3513
3438
|
const top = findUp(cwd, ".git") ?? null;
|
|
3514
3439
|
if (top === null) return { roots: [], workspace: null };
|
|
3515
3440
|
const configs = await findFiles(cwd, [`**/${PROJECT_FILE}`]);
|
|
3516
3441
|
const roots = [];
|
|
3517
3442
|
for (const config of configs) {
|
|
3518
|
-
const dir =
|
|
3443
|
+
const dir = resolve9(cwd, dirname9(config));
|
|
3519
3444
|
if (await realpath5(findUp(dir, ".git") ?? dir) === await realpath5(top)) roots.push(dir);
|
|
3520
3445
|
}
|
|
3521
3446
|
return { roots, workspace: null };
|
|
@@ -3528,7 +3453,7 @@ async function workspaceStatus(cwd, named2) {
|
|
|
3528
3453
|
projects.push(await projectStatus(await loadProject(root), cwd));
|
|
3529
3454
|
} catch (error) {
|
|
3530
3455
|
const label = placeOf(cwd, root);
|
|
3531
|
-
projects.push({ root: label, error: error instanceof Error ? error.message : String(error), next: await readTextOrNull(
|
|
3456
|
+
projects.push({ root: label, error: error instanceof Error ? error.message : String(error), next: await readTextOrNull(join18(root, PROJECT_FILE)) === null ? `youiyoux adopt or youiyoux init --design <dir> in ${label}` : `fix ${join18(label, PROJECT_FILE)}` });
|
|
3532
3457
|
}
|
|
3533
3458
|
}
|
|
3534
3459
|
return { schema: "youi.status/v1", generatedAt: (/* @__PURE__ */ new Date()).toISOString(), workspace: workspace ? relative8(cwd, workspace) || WORKSPACE_FILE : null, projects };
|
|
@@ -3545,7 +3470,8 @@ function projectLines(s) {
|
|
|
3545
3470
|
const counts = `${check.errors > 0 ? style.error(plural(check.errors, "error")) : style.ok("0 errors")} \xB7 ${plural(check.warnings, "warning")}`;
|
|
3546
3471
|
const baseline = check.baseline ? style.dim(` beyond the baseline (${check.baseline.known} accepted${check.baseline.fixed > 0 ? `, ${check.baseline.fixed} fixed` : ""})`) : "";
|
|
3547
3472
|
return [
|
|
3548
|
-
|
|
3473
|
+
// The folder, when it says more than the name: never "." (here) or the id again.
|
|
3474
|
+
`${style.bold(s.id)}${s.root === s.id || s.root === "." ? "" : ` ${style.dim(`\xB7 ${s.root}`)}`} \xB7 ${s.system.name} v${s.system.version} ${style.dim(`(${s.system.source}${s.system.linked ? ", linked" : ""}) \xB7 ${synced}`)}`,
|
|
3549
3475
|
row("sync", sync),
|
|
3550
3476
|
row("drift", drift),
|
|
3551
3477
|
row("check", `${counts}${baseline}${check.incomplete ? style.warn(" \xB7 incomplete: not a pass") : ""}`),
|
|
@@ -3569,7 +3495,7 @@ var git3 = async (cwd, args) => run6("git", args, { cwd }).then((r) => r.stdout.
|
|
|
3569
3495
|
var HUB_URL_ENV = "YOUIYOUX_HUB_URL";
|
|
3570
3496
|
var HUB_TOKEN_ENV = "YOUIYOUX_HUB_TOKEN";
|
|
3571
3497
|
function toolVersion(root = TOOL_ROOT) {
|
|
3572
|
-
for (const file of [
|
|
3498
|
+
for (const file of [join19(root, "packages/youiyoux/package.json"), join19(root, "../package.json")]) {
|
|
3573
3499
|
try {
|
|
3574
3500
|
const pkg = JSON.parse(readFileSync2(file, "utf8"));
|
|
3575
3501
|
if (pkg.name === "youiyoux" && pkg.version) return pkg.version;
|
|
@@ -3622,7 +3548,7 @@ function renderRecord(record, sentTo) {
|
|
|
3622
3548
|
}
|
|
3623
3549
|
|
|
3624
3550
|
// ../cli/src/workspace-hub.ts
|
|
3625
|
-
import { randomBytes
|
|
3551
|
+
import { randomBytes } from "node:crypto";
|
|
3626
3552
|
import { createServer as createServer2 } from "node:http";
|
|
3627
3553
|
var KEY_HEADER = "x-youi-session";
|
|
3628
3554
|
function send2(res, status, body) {
|
|
@@ -3638,7 +3564,7 @@ async function readBody2(req) {
|
|
|
3638
3564
|
return text ? JSON.parse(text) : {};
|
|
3639
3565
|
}
|
|
3640
3566
|
async function startWorkspaceHub(options) {
|
|
3641
|
-
const key2 =
|
|
3567
|
+
const key2 = randomBytes(18).toString("base64url");
|
|
3642
3568
|
let report = await options.status();
|
|
3643
3569
|
let current = options.current;
|
|
3644
3570
|
let busy = false;
|
|
@@ -3684,13 +3610,13 @@ async function startWorkspaceHub(options) {
|
|
|
3684
3610
|
|
|
3685
3611
|
// ../cli/src/index-store.ts
|
|
3686
3612
|
import { appendFile, mkdir as mkdir4, readFile as readFile8, stat as stat2, rename as rename2, mkdtemp as mkdtemp4, rm as rm6 } from "node:fs/promises";
|
|
3687
|
-
import { dirname as dirname10, join as
|
|
3613
|
+
import { dirname as dirname10, join as join20, resolve as resolve10 } from "node:path";
|
|
3688
3614
|
var SOURCES_FILE = "index-sources.json";
|
|
3689
3615
|
var SCANS_LOG = "scans.jsonl";
|
|
3690
3616
|
var EMPTY = { discover: null, inventories: [], projects: [] };
|
|
3691
3617
|
async function readIndexSources(home) {
|
|
3692
3618
|
try {
|
|
3693
|
-
const raw = JSON.parse(await readFile8(
|
|
3619
|
+
const raw = JSON.parse(await readFile8(join20(home, SOURCES_FILE), "utf8"));
|
|
3694
3620
|
return { discover: raw.discover ?? null, inventories: raw.inventories ?? [], projects: raw.projects ?? [] };
|
|
3695
3621
|
} catch {
|
|
3696
3622
|
return EMPTY;
|
|
@@ -3703,14 +3629,14 @@ async function noteSource(home, change) {
|
|
|
3703
3629
|
inventories: change.inventory && !sources.inventories.includes(change.inventory) ? [...sources.inventories, change.inventory] : sources.inventories,
|
|
3704
3630
|
projects: change.project ? [...sources.projects.filter((p) => p.root !== change.project.root), change.project] : sources.projects
|
|
3705
3631
|
};
|
|
3706
|
-
await writeFileAtomic(
|
|
3632
|
+
await writeFileAtomic(join20(home, SOURCES_FILE), `${JSON.stringify(next2, null, 2)}
|
|
3707
3633
|
`);
|
|
3708
3634
|
}
|
|
3709
3635
|
async function recordInventory(store, home, report, file) {
|
|
3710
|
-
const run8 = inventoryRun(report,
|
|
3636
|
+
const run8 = inventoryRun(report, resolve10(file));
|
|
3711
3637
|
const logged = { run: run8.run, source: run8.source, scannedAt: run8.scannedAt, projects: run8.projects, families: run8.families };
|
|
3712
3638
|
await mkdir4(home, { recursive: true });
|
|
3713
|
-
await appendFile(
|
|
3639
|
+
await appendFile(join20(home, SCANS_LOG), `${JSON.stringify({ schema: "youi.scan-log/v1", ...logged })}
|
|
3714
3640
|
`);
|
|
3715
3641
|
await store.recordInventory(run8);
|
|
3716
3642
|
await noteSource(home, { inventory: run8.source });
|
|
@@ -3721,7 +3647,7 @@ async function recordProject(store, project2, usage) {
|
|
|
3721
3647
|
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 }));
|
|
3722
3648
|
}
|
|
3723
3649
|
async function readLog(home) {
|
|
3724
|
-
const text = await readFile8(
|
|
3650
|
+
const text = await readFile8(join20(home, SCANS_LOG), "utf8").catch(() => "");
|
|
3725
3651
|
return text.split("\n").flatMap((line) => {
|
|
3726
3652
|
if (!line.trim()) return [];
|
|
3727
3653
|
try {
|
|
@@ -3738,7 +3664,7 @@ async function rebuildIndex(path, options = {}) {
|
|
|
3738
3664
|
const home = indexHome(path, env);
|
|
3739
3665
|
await mkdir4(dirname10(path), { recursive: true });
|
|
3740
3666
|
const scratch = !env.DATABASE_URL ? await mkdtemp4(`${path}.rebuild-`) : null;
|
|
3741
|
-
const target = scratch ?
|
|
3667
|
+
const target = scratch ? join20(scratch, "index.db") : path;
|
|
3742
3668
|
const store = scratch ? await openSqlite(target) : await sharedStore(path, env);
|
|
3743
3669
|
try {
|
|
3744
3670
|
if (env.DATABASE_URL) await store.reset();
|
|
@@ -3746,7 +3672,7 @@ async function rebuildIndex(path, options = {}) {
|
|
|
3746
3672
|
const sources = await readIndexSources(home);
|
|
3747
3673
|
const cache = options.discoverCache ?? sources.discover;
|
|
3748
3674
|
let discover = { cache, chosen: 0, all: 0 };
|
|
3749
|
-
if (cache && await stat2(
|
|
3675
|
+
if (cache && await stat2(join20(cache, "index.json")).then(() => true, () => false)) {
|
|
3750
3676
|
const loaded = await ingestCatalog(store, cache);
|
|
3751
3677
|
discover = { cache, chosen: loaded.chosen, all: loaded.all };
|
|
3752
3678
|
}
|
|
@@ -3774,7 +3700,7 @@ async function rebuildIndex(path, options = {}) {
|
|
|
3774
3700
|
}
|
|
3775
3701
|
try {
|
|
3776
3702
|
const project2 = await loadProject(source.root, source.options);
|
|
3777
|
-
const usage = ScanReport.safeParse(await readJson(source.usage ??
|
|
3703
|
+
const usage = ScanReport.safeParse(await readJson(source.usage ?? join20(project2.root, ".youi/usage.json")));
|
|
3778
3704
|
await recordProject(store, project2, usage.success ? usage.data : null);
|
|
3779
3705
|
projects++;
|
|
3780
3706
|
} catch (error) {
|
|
@@ -3991,9 +3917,9 @@ function renderAdoptionRequest(request) {
|
|
|
3991
3917
|
}
|
|
3992
3918
|
|
|
3993
3919
|
// ../cli/src/report/run.ts
|
|
3994
|
-
import { randomBytes as
|
|
3920
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
3995
3921
|
import { mkdir as mkdir5, rename as rename3, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
|
|
3996
|
-
import { join as
|
|
3922
|
+
import { join as join26, relative as relative10, resolve as resolve13 } from "node:path";
|
|
3997
3923
|
|
|
3998
3924
|
// ../cli/src/report/card.ts
|
|
3999
3925
|
import { deflateSync } from "node:zlib";
|
|
@@ -4229,15 +4155,15 @@ function drawCard(input) {
|
|
|
4229
4155
|
|
|
4230
4156
|
// ../cli/src/report/model.ts
|
|
4231
4157
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
4232
|
-
import { join as
|
|
4158
|
+
import { join as join24 } from "node:path";
|
|
4233
4159
|
|
|
4234
4160
|
// ../cli/src/report/groups.ts
|
|
4235
|
-
import { existsSync as
|
|
4236
|
-
import { join as
|
|
4161
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
4162
|
+
import { join as join22 } from "node:path";
|
|
4237
4163
|
|
|
4238
4164
|
// ../cli/src/report/imports.ts
|
|
4239
4165
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
4240
|
-
import { dirname as dirname11, join as
|
|
4166
|
+
import { dirname as dirname11, join as join21, relative as relative9, resolve as resolve11 } from "node:path";
|
|
4241
4167
|
import ts from "typescript";
|
|
4242
4168
|
var resolvers = /* @__PURE__ */ new Map();
|
|
4243
4169
|
function resolverOf(root) {
|
|
@@ -4256,13 +4182,13 @@ function clearImportCache() {
|
|
|
4256
4182
|
}
|
|
4257
4183
|
async function verifiedImport(root, keeper, from, suggested) {
|
|
4258
4184
|
const { options, cache } = resolverOf(root);
|
|
4259
|
-
let local = relative9(dirname11(
|
|
4185
|
+
let local = relative9(dirname11(join21(root, from)), join21(root, keeper)).replaceAll("\\", "/").replace(/\.(tsx?|jsx?|mjs)$/, "");
|
|
4260
4186
|
if (!local.startsWith(".")) local = `./${local}`;
|
|
4261
4187
|
for (const specifier of /* @__PURE__ */ new Set([suggested, local])) {
|
|
4262
|
-
const found = ts.resolveModuleName(specifier,
|
|
4188
|
+
const found = ts.resolveModuleName(specifier, resolve11(root, from), options, ts.sys, cache).resolvedModule?.resolvedFileName;
|
|
4263
4189
|
if (found) {
|
|
4264
4190
|
try {
|
|
4265
|
-
if (realpathSync2(found) === realpathSync2(
|
|
4191
|
+
if (realpathSync2(found) === realpathSync2(join21(root, keeper))) return specifier;
|
|
4266
4192
|
} catch {
|
|
4267
4193
|
}
|
|
4268
4194
|
}
|
|
@@ -4670,7 +4596,7 @@ function factsOf(project2, id, modules, eligible, workspaceNames, dependencies,
|
|
|
4670
4596
|
if (dirs.has(file.slice(0, at))) break;
|
|
4671
4597
|
dirs.add(file.slice(0, at));
|
|
4672
4598
|
}
|
|
4673
|
-
const roots = [...dirs].filter((dir) =>
|
|
4599
|
+
const roots = [...dirs].filter((dir) => existsSync2(join22(project2.root, dir, "package.json"))).sort((a, b) => b.length - a.length);
|
|
4674
4600
|
const nested = (file) => roots.find((dir) => file.startsWith(`${dir}/`)) ?? "";
|
|
4675
4601
|
return { project: project2, id, dependencies, packageImports, jsxCounts, eligible, twins, dirs, importer, packageOf: nested };
|
|
4676
4602
|
}
|
|
@@ -4678,11 +4604,11 @@ function factsOf(project2, id, modules, eligible, workspaceNames, dependencies,
|
|
|
4678
4604
|
// ../cli/src/report/projects.ts
|
|
4679
4605
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
4680
4606
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
4681
|
-
import { basename as basename4, join as
|
|
4607
|
+
import { basename as basename4, join as join23, resolve as resolve12 } from "node:path";
|
|
4682
4608
|
var UI_FILES = ["**/*.{tsx,jsx,astro,vue,svelte}"];
|
|
4683
4609
|
var strings = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "string") : [];
|
|
4684
4610
|
async function workspaceGlobs(root, pkg) {
|
|
4685
|
-
const pnpm = await readFile9(
|
|
4611
|
+
const pnpm = await readFile9(join23(root, "pnpm-workspace.yaml"), "utf8").catch(() => null);
|
|
4686
4612
|
if (pnpm !== null) {
|
|
4687
4613
|
try {
|
|
4688
4614
|
const globs2 = strings((0, import_yaml3.parse)(pnpm)?.packages);
|
|
@@ -4696,8 +4622,8 @@ async function workspaceGlobs(root, pkg) {
|
|
|
4696
4622
|
}
|
|
4697
4623
|
var hasUi = async (dir) => (await findFiles(dir, UI_FILES, DEFAULT_EXCLUDE)).length > 0;
|
|
4698
4624
|
async function findProjects(dir) {
|
|
4699
|
-
const root =
|
|
4700
|
-
const pkg = await readJson(
|
|
4625
|
+
const root = resolve12(dir);
|
|
4626
|
+
const pkg = await readJson(join23(root, "package.json"));
|
|
4701
4627
|
const name = typeof pkg?.name === "string" && pkg.name.trim() ? pkg.name.trim() : basename4(root);
|
|
4702
4628
|
const single = { dir: ".", root, name: typeof pkg?.name === "string" ? pkg.name : null };
|
|
4703
4629
|
const workspace = await workspaceGlobs(root, pkg);
|
|
@@ -4708,12 +4634,12 @@ async function findProjects(dir) {
|
|
|
4708
4634
|
const projects = [];
|
|
4709
4635
|
const skipped = [];
|
|
4710
4636
|
for (const member of members) {
|
|
4711
|
-
const memberRoot =
|
|
4637
|
+
const memberRoot = join23(root, member);
|
|
4712
4638
|
if (!await hasUi(memberRoot)) {
|
|
4713
4639
|
skipped.push(member);
|
|
4714
4640
|
continue;
|
|
4715
4641
|
}
|
|
4716
|
-
const memberPkg = await readJson(
|
|
4642
|
+
const memberPkg = await readJson(join23(memberRoot, "package.json"));
|
|
4717
4643
|
projects.push({ dir: member, root: memberRoot, name: typeof memberPkg?.name === "string" ? memberPkg.name : null });
|
|
4718
4644
|
}
|
|
4719
4645
|
if (projects.length === 0) return { root, name, layout: `one project (${workspace.source} names no package with UI files)`, projects: [single], skipped };
|
|
@@ -4732,15 +4658,15 @@ var Lines = class {
|
|
|
4732
4658
|
files = /* @__PURE__ */ new Map();
|
|
4733
4659
|
root;
|
|
4734
4660
|
enabled;
|
|
4735
|
-
constructor(root,
|
|
4661
|
+
constructor(root, enabled) {
|
|
4736
4662
|
this.root = root;
|
|
4737
|
-
this.enabled =
|
|
4663
|
+
this.enabled = enabled;
|
|
4738
4664
|
}
|
|
4739
4665
|
async site(at, file, line) {
|
|
4740
4666
|
if (!this.enabled) return { at };
|
|
4741
4667
|
let lines = this.files.get(file);
|
|
4742
4668
|
if (!lines) {
|
|
4743
|
-
lines = (await readFile10(
|
|
4669
|
+
lines = (await readFile10(join24(this.root, file), "utf8").catch(() => "")).split("\n");
|
|
4744
4670
|
this.files.set(file, lines);
|
|
4745
4671
|
}
|
|
4746
4672
|
const code = lines[line - 1]?.trim();
|
|
@@ -4760,7 +4686,7 @@ async function modulesOf(project2, target, failed3) {
|
|
|
4760
4686
|
for (const file of target.files) {
|
|
4761
4687
|
if (isShowcase(file)) continue;
|
|
4762
4688
|
try {
|
|
4763
|
-
const module = await parseModule(file, await readFile10(
|
|
4689
|
+
const module = await parseModule(file, await readFile10(join24(project2.root, file), "utf8"));
|
|
4764
4690
|
if (module) modules.push(module);
|
|
4765
4691
|
} catch (error) {
|
|
4766
4692
|
failed3.push(`${repoPath(project2.dir, file)}: ${errorText(error)}`);
|
|
@@ -4864,7 +4790,7 @@ async function analyseProject(project2, index, inventory, inventoryError, worksp
|
|
|
4864
4790
|
incomplete.push(`Library choices were not compared (${errorText(error)}); run ${NPX} detect ${project2.dir} to see why`);
|
|
4865
4791
|
}
|
|
4866
4792
|
}
|
|
4867
|
-
const pkg = await readFile10(
|
|
4793
|
+
const pkg = await readFile10(join24(project2.root, "package.json"), "utf8").then((text) => JSON.parse(text), () => null);
|
|
4868
4794
|
const dependencies = new Set(["dependencies", "devDependencies", "peerDependencies"].flatMap((key2) => Object.keys(pkg?.[key2] ?? {})));
|
|
4869
4795
|
const importer = changeProject ? await importOf(changeProject) : () => "";
|
|
4870
4796
|
const facts = factsOf(project2, projectId ?? null, modules, eligible, workspaceNames, dependencies, target?.files ?? [], importer);
|
|
@@ -5306,9 +5232,9 @@ ${model.projects.map((p) => projectSection(p, many, looks)).join("\n")}
|
|
|
5306
5232
|
|
|
5307
5233
|
// ../cli/src/report/looks.ts
|
|
5308
5234
|
import { spawn as spawn2 } from "node:child_process";
|
|
5309
|
-
import { existsSync as
|
|
5310
|
-
import { homedir as
|
|
5311
|
-
import { dirname as dirname12, join as
|
|
5235
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
5236
|
+
import { homedir as homedir2 } from "node:os";
|
|
5237
|
+
import { dirname as dirname12, join as join25 } from "node:path";
|
|
5312
5238
|
var LOOKS_PER_PROJECT = 4;
|
|
5313
5239
|
var DOWNLOAD_SIZE = "~100 MB";
|
|
5314
5240
|
var DEPENDENCIES = "Install the repo's dependencies to see rendered looks";
|
|
@@ -5316,31 +5242,31 @@ var UNDRAWABLE = /not installed|loads no stylesheet|drawn from (?:its|their) (?:
|
|
|
5316
5242
|
var playwrightDir = () => dirname12(playwrightCli());
|
|
5317
5243
|
function browsersPath(env) {
|
|
5318
5244
|
const set = env.PLAYWRIGHT_BROWSERS_PATH;
|
|
5319
|
-
if (set === "0") return
|
|
5245
|
+
if (set === "0") return join25(playwrightDir(), ".local-browsers");
|
|
5320
5246
|
if (set) return set;
|
|
5321
|
-
if (process.platform === "darwin") return
|
|
5322
|
-
if (process.platform === "win32") return
|
|
5323
|
-
return
|
|
5247
|
+
if (process.platform === "darwin") return join25(homedir2(), "Library/Caches/ms-playwright");
|
|
5248
|
+
if (process.platform === "win32") return join25(env.LOCALAPPDATA ?? join25(homedir2(), "AppData/Local"), "ms-playwright");
|
|
5249
|
+
return join25(env.XDG_CACHE_HOME ?? join25(homedir2(), ".cache"), "ms-playwright");
|
|
5324
5250
|
}
|
|
5325
5251
|
function chromiumStatus(env = process.env) {
|
|
5326
|
-
if (env.YOUI_CHROMIUM) return { available:
|
|
5252
|
+
if (env.YOUI_CHROMIUM) return { available: existsSync3(env.YOUI_CHROMIUM), where: env.YOUI_CHROMIUM };
|
|
5327
5253
|
try {
|
|
5328
|
-
const browsers = JSON.parse(readFileSync3(
|
|
5254
|
+
const browsers = JSON.parse(readFileSync3(join25(playwrightDir(), "browsers.json"), "utf8"));
|
|
5329
5255
|
const revision2 = browsers.browsers.find((b) => b.name === "chromium-headless-shell")?.revision;
|
|
5330
|
-
const dir =
|
|
5331
|
-
return { available: revision2 !== void 0 &&
|
|
5256
|
+
const dir = join25(browsersPath(env), `chromium_headless_shell-${revision2}`);
|
|
5257
|
+
return { available: revision2 !== void 0 && existsSync3(join25(dir, "INSTALLATION_COMPLETE")), where: dir };
|
|
5332
5258
|
} catch {
|
|
5333
5259
|
return { available: false, where: "playwright-core is not installed" };
|
|
5334
5260
|
}
|
|
5335
5261
|
}
|
|
5336
5262
|
function downloadChromium() {
|
|
5337
|
-
return new Promise((
|
|
5338
|
-
const child = spawn2(process.execPath, [
|
|
5339
|
-
child.on("error", () =>
|
|
5340
|
-
child.on("close", (code) =>
|
|
5263
|
+
return new Promise((resolve15) => {
|
|
5264
|
+
const child = spawn2(process.execPath, [join25(playwrightDir(), "cli.js"), "install", "chromium-headless-shell"], { stdio: ["ignore", 2, 2] });
|
|
5265
|
+
child.on("error", () => resolve15(false));
|
|
5266
|
+
child.on("close", (code) => resolve15(code === 0));
|
|
5341
5267
|
});
|
|
5342
5268
|
}
|
|
5343
|
-
var dataUri = (file) => file &&
|
|
5269
|
+
var dataUri = (file) => file && existsSync3(file) ? `data:image/png;base64,${readFileSync3(file).toString("base64")}` : null;
|
|
5344
5270
|
async function addLooks(model, repoRoot, options = {}) {
|
|
5345
5271
|
const drawn = [];
|
|
5346
5272
|
const problems = [];
|
|
@@ -5351,9 +5277,9 @@ async function addLooks(model, repoRoot, options = {}) {
|
|
|
5351
5277
|
const where2 = section.dir === "." ? "this repo" : section.dir;
|
|
5352
5278
|
try {
|
|
5353
5279
|
const installed = (name) => {
|
|
5354
|
-
let dir =
|
|
5280
|
+
let dir = join25(repoRoot, section.dir);
|
|
5355
5281
|
while (true) {
|
|
5356
|
-
if (
|
|
5282
|
+
if (existsSync3(join25(dir, "node_modules", name, "package.json"))) return true;
|
|
5357
5283
|
if (dir === repoRoot || dirname12(dir) === dir) return false;
|
|
5358
5284
|
dir = dirname12(dir);
|
|
5359
5285
|
}
|
|
@@ -5362,13 +5288,13 @@ async function addLooks(model, repoRoot, options = {}) {
|
|
|
5362
5288
|
missing.push(where2);
|
|
5363
5289
|
continue;
|
|
5364
5290
|
}
|
|
5365
|
-
const projectRoot =
|
|
5291
|
+
const projectRoot = join25(repoRoot, section.dir);
|
|
5366
5292
|
const target = await loadInventoryTarget(projectRoot);
|
|
5367
5293
|
if (findStylesheets(projectRoot, target.files, { tsconfig: target.tsconfig, override: target.specimenCss, templates: target.templates }).found.length === 0) {
|
|
5368
5294
|
missing.push(where2);
|
|
5369
5295
|
continue;
|
|
5370
5296
|
}
|
|
5371
|
-
const report = await renderShots(
|
|
5297
|
+
const report = await renderShots(join25(repoRoot, section.dir), names, { download: false, base: "HEAD", ...options.executablePath ? { executablePath: options.executablePath } : {}, ...options.cache ? { cache: options.cache } : {}, ...options.log ? { log: options.log } : {} });
|
|
5372
5298
|
const unavailable = report.notes.some((note) => UNDRAWABLE.test(note));
|
|
5373
5299
|
if (unavailable) {
|
|
5374
5300
|
missing.push(where2);
|
|
@@ -5450,7 +5376,7 @@ async function askTerminal(question) {
|
|
|
5450
5376
|
}
|
|
5451
5377
|
}
|
|
5452
5378
|
async function writeBinaryAtomic(file, bytes) {
|
|
5453
|
-
const temp = `${file}.${process.pid}.${
|
|
5379
|
+
const temp = `${file}.${process.pid}.${randomBytes2(6).toString("hex")}.tmp`;
|
|
5454
5380
|
await writeFile2(temp, bytes);
|
|
5455
5381
|
await rename3(temp, file);
|
|
5456
5382
|
}
|
|
@@ -5464,7 +5390,7 @@ async function runReport(options = {}, io = {}) {
|
|
|
5464
5390
|
const error = io.error ?? ((text) => void process.stderr.write(`${text}
|
|
5465
5391
|
`));
|
|
5466
5392
|
const env = io.env ?? process.env;
|
|
5467
|
-
const root =
|
|
5393
|
+
const root = resolve13(options.path ?? process.cwd());
|
|
5468
5394
|
if (!(await stat3(root).catch(() => null))?.isDirectory()) {
|
|
5469
5395
|
error(`\u2716 ${options.path ?? root} is not a directory: run ${NPX} in a repo, or pass its path (${NPX} path/to/repo)`);
|
|
5470
5396
|
return { code: 2, files: null, model: null };
|
|
@@ -5494,9 +5420,9 @@ async function runReport(options = {}, io = {}) {
|
|
|
5494
5420
|
model.durationMs += Math.round(performance.now() - started);
|
|
5495
5421
|
const redactor = await Redactor.forRepo(root, { includeCode: options.includeCode === true, env });
|
|
5496
5422
|
const clean = redactor.model(model);
|
|
5497
|
-
const outDir =
|
|
5423
|
+
const outDir = resolve13(options.out ?? root);
|
|
5498
5424
|
await mkdir5(outDir, { recursive: true });
|
|
5499
|
-
const files = { report:
|
|
5425
|
+
const files = { report: join26(outDir, REPORT_FILE), card: join26(outDir, CARD_FILE), summary: join26(outDir, SUMMARY_FILE) };
|
|
5500
5426
|
const t = clean.totals;
|
|
5501
5427
|
const card = {
|
|
5502
5428
|
repo: redactor.scrub(clean.repo),
|
|
@@ -5672,6 +5598,12 @@ ${style.bold("System")} ${style.dim("approved elements: build only with these")
|
|
|
5672
5598
|
${style.bold("Library")} ${style.dim("ingested references: browse and request adoption, never build with")}
|
|
5673
5599
|
library search <query> Library items (lib: ids) and the System elements each could swap in for
|
|
5674
5600
|
library request <id> --reason <text> draft an adoption request for a person to approve
|
|
5601
|
+
library ingest <link> [--draft] [--json]
|
|
5602
|
+
read what a GitHub repository, a Storybook, a Figma file (FIGMA_TOKEN) or a
|
|
5603
|
+
DESIGN.md holds into Library items, each sorted into a role, and show them;
|
|
5604
|
+
--draft files them as one draft in the changes queue, where a person keeps or
|
|
5605
|
+
drops each and approves the rest (youiyoux ui > Changes). GITHUB_TOKEN raises
|
|
5606
|
+
GitHub's 60 requests an hour
|
|
5675
5607
|
|
|
5676
5608
|
${style.bold("Discover")} ${style.dim("UI components by need, across shadcn registries and npm: candidates, never installed")}
|
|
5677
5609
|
discover sync [--cache dir] [--max-registries n] [--icons]
|
|
@@ -5787,6 +5719,7 @@ var OPTIONS = {
|
|
|
5787
5719
|
host: { type: "string" },
|
|
5788
5720
|
db: { type: "string" },
|
|
5789
5721
|
record: { type: "boolean", default: false },
|
|
5722
|
+
draft: { type: "boolean", default: false },
|
|
5790
5723
|
cache: { type: "string" },
|
|
5791
5724
|
role: { type: "string" },
|
|
5792
5725
|
license: { type: "string" },
|
|
@@ -5824,10 +5757,10 @@ async function readJsonOrFile(value) {
|
|
|
5824
5757
|
async function cmdScan(values) {
|
|
5825
5758
|
const p = await project(values);
|
|
5826
5759
|
const { report } = await scanProject(p);
|
|
5827
|
-
const out = values.out ??
|
|
5828
|
-
await writeFileAtomic(
|
|
5760
|
+
const out = values.out ?? join27(p.root, ".youi/usage.json");
|
|
5761
|
+
await writeFileAtomic(resolve14(out), `${JSON.stringify(report)}
|
|
5829
5762
|
`);
|
|
5830
|
-
const recorded = await recordUsage(values, p, report,
|
|
5763
|
+
const recorded = await recordUsage(values, p, report, resolve14(out));
|
|
5831
5764
|
if (values.json) json3(report);
|
|
5832
5765
|
else print([renderScan(report, out), ...recorded ? [recorded] : []].join("\n"));
|
|
5833
5766
|
return 0;
|
|
@@ -5836,7 +5769,7 @@ async function recordUsage(values, p, report, usage) {
|
|
|
5836
5769
|
const { path, home } = indexOf(values);
|
|
5837
5770
|
try {
|
|
5838
5771
|
await recordProject(await sharedStore(path), p, report);
|
|
5839
|
-
await noteSource(home, { project: { root:
|
|
5772
|
+
await noteSource(home, { project: { root: resolve14(values.project ?? process.cwd()), options: Object.fromEntries(Object.entries(loadOptions(values)).map(([key2, value]) => [key2, resolve14(value)])), usage } });
|
|
5840
5773
|
return null;
|
|
5841
5774
|
} catch (error) {
|
|
5842
5775
|
return notRecorded(error);
|
|
@@ -5851,17 +5784,17 @@ function indexOf(values) {
|
|
|
5851
5784
|
}
|
|
5852
5785
|
async function cmdGaps(values) {
|
|
5853
5786
|
const dirs = inventoryDirs(values);
|
|
5854
|
-
const inventory = values.inventory ? InventoryReport.parse(JSON.parse(await readFile11(
|
|
5855
|
-
const cwd = values.inventory ? dirname13(
|
|
5856
|
-
const project2 = await loadProject(
|
|
5787
|
+
const inventory = values.inventory ? InventoryReport.parse(JSON.parse(await readFile11(resolve14(values.inventory), "utf8"))) : await scanInventory(values, dirs);
|
|
5788
|
+
const cwd = values.inventory ? dirname13(resolve14(values.inventory)) : process.cwd();
|
|
5789
|
+
const project2 = await loadProject(resolve14(dirs[0]), loadOptions(values)).catch(() => null);
|
|
5857
5790
|
const system = project2 ? { name: project2.system.config.name, components: project2.system.components.map((c) => c.contract.name) } : null;
|
|
5858
|
-
const store = await readCatalog(
|
|
5791
|
+
const store = await readCatalog(resolve14(discoverCacheDir(values.cache)), indexOf(values).path).catch((error) => {
|
|
5859
5792
|
if (error instanceof MissingIndexError) return null;
|
|
5860
5793
|
throw error;
|
|
5861
5794
|
});
|
|
5862
|
-
const roots = new Map(inventory.projects.map((p) => [p.id,
|
|
5795
|
+
const roots = new Map(inventory.projects.map((p) => [p.id, resolve14(cwd, p.root)]));
|
|
5863
5796
|
const report = await buildGaps({ inventory, system, dependencies: declaredPackages(roots) }, store);
|
|
5864
|
-
if (values.out) await writeFileAtomic(
|
|
5797
|
+
if (values.out) await writeFileAtomic(resolve14(values.out), `${JSON.stringify(report, null, 2)}
|
|
5865
5798
|
`);
|
|
5866
5799
|
if (values.json) json3(report);
|
|
5867
5800
|
else print(renderGaps(report));
|
|
@@ -5871,7 +5804,7 @@ async function cmdInventory(values) {
|
|
|
5871
5804
|
if (values.history) return cmdHistory(values, []);
|
|
5872
5805
|
const dirs = inventoryDirs(values);
|
|
5873
5806
|
const report = await scanInventory(values, dirs);
|
|
5874
|
-
const out =
|
|
5807
|
+
const out = resolve14(values.out ?? join27(dirs[0], ".youi/inventory.json"));
|
|
5875
5808
|
await writeFileAtomic(out, `${JSON.stringify(report, null, 2)}
|
|
5876
5809
|
`);
|
|
5877
5810
|
const recorded = await recordScan(values, report, out);
|
|
@@ -5901,7 +5834,7 @@ async function cmdIndex(values, positionals) {
|
|
|
5901
5834
|
const [action, ...rest] = positionals;
|
|
5902
5835
|
const { path, home } = indexOf(values);
|
|
5903
5836
|
if (action === "path") {
|
|
5904
|
-
if (values.json) json3({ store: storeLocation({ path }), sources:
|
|
5837
|
+
if (values.json) json3({ store: storeLocation({ path }), sources: join27(home, SOURCES_FILE), scans: join27(home, SCANS_LOG) });
|
|
5905
5838
|
else print(storeLocation({ path }));
|
|
5906
5839
|
return 0;
|
|
5907
5840
|
}
|
|
@@ -5912,7 +5845,7 @@ async function cmdIndex(values, positionals) {
|
|
|
5912
5845
|
return 0;
|
|
5913
5846
|
}
|
|
5914
5847
|
if (action === "rebuild") {
|
|
5915
|
-
const summary = await rebuildIndex(path, values.cache ? { discoverCache:
|
|
5848
|
+
const summary = await rebuildIndex(path, values.cache ? { discoverCache: resolve14(values.cache) } : {});
|
|
5916
5849
|
if (values.json) json3(summary);
|
|
5917
5850
|
else print(renderRebuild(summary));
|
|
5918
5851
|
return 0;
|
|
@@ -5952,7 +5885,7 @@ async function cmdBom(values, positionals) {
|
|
|
5952
5885
|
return 0;
|
|
5953
5886
|
}
|
|
5954
5887
|
function baselineFile(values, p) {
|
|
5955
|
-
if (values["baseline-file"]) return
|
|
5888
|
+
if (values["baseline-file"]) return resolve14(values["baseline-file"]);
|
|
5956
5889
|
return values.baseline ? baselinePath(p, values.config) : null;
|
|
5957
5890
|
}
|
|
5958
5891
|
var checkScope = (values, positionals) => ({ ...positionals.length > 0 ? { files: positionals } : {}, ...values.rule ? { rule: values.rule } : {}, quiet: values.quiet });
|
|
@@ -6067,7 +6000,16 @@ async function cmdLibrary(values, positionals) {
|
|
|
6067
6000
|
else print(renderAdoptionRequest(request));
|
|
6068
6001
|
return 0;
|
|
6069
6002
|
}
|
|
6070
|
-
|
|
6003
|
+
if (action === "ingest" && query && positionals.length === 2) {
|
|
6004
|
+
const { fileIngestDraft, readLink, renderIngest } = await import("./ingest-OF4Z33L2.js");
|
|
6005
|
+
const p = values.draft ? await project(values) : null;
|
|
6006
|
+
const reading = await readLink(query, { allowLocal: true });
|
|
6007
|
+
const filed = p ? await fileIngestDraft(p, reading, values.state) : null;
|
|
6008
|
+
if (values.json) json3({ ...reading, ...filed ? { draft: filed.id } : {} });
|
|
6009
|
+
else print(renderIngest(reading, filed));
|
|
6010
|
+
return 0;
|
|
6011
|
+
}
|
|
6012
|
+
throw new UsageError("youiyoux library search <query> or youiyoux library request <id> --reason <text> or youiyoux library ingest <link> [--draft]");
|
|
6071
6013
|
}
|
|
6072
6014
|
async function cmdSync(values) {
|
|
6073
6015
|
const p = await loadProject(values.project ?? process.cwd(), { ...loadOptions(values), refreshDesign: true });
|
|
@@ -6091,7 +6033,7 @@ async function cmdRecord(values) {
|
|
|
6091
6033
|
const github = values.send ? await requestGithubToken(audienceOf(hub)) : null;
|
|
6092
6034
|
if (values.send && !token && !github) throw new UsageError(`youiyoux record --send needs a way to prove where the record comes from: in GitHub Actions, permissions: id-token: write; elsewhere, the hub's ingest token in ${HUB_TOKEN_ENV} (from the environment only, never a flag)`);
|
|
6093
6035
|
const record = await buildRecord(values.project ?? process.cwd(), values.repo ? { repo: values.repo } : {});
|
|
6094
|
-
if (values.out) await writeFileAtomic(
|
|
6036
|
+
if (values.out) await writeFileAtomic(resolve14(values.out), `${JSON.stringify(record, null, 2)}
|
|
6095
6037
|
`);
|
|
6096
6038
|
const sentTo = values.send ? await sendRecord(record, hub, { token, github }) : null;
|
|
6097
6039
|
if (values.json) json3(record);
|
|
@@ -6099,7 +6041,7 @@ async function cmdRecord(values) {
|
|
|
6099
6041
|
return 0;
|
|
6100
6042
|
}
|
|
6101
6043
|
function builtHub() {
|
|
6102
|
-
for (const dir of [
|
|
6044
|
+
for (const dir of [join27(TOOL_ROOT, "hub"), join27(TOOL_ROOT, "apps/web/dist")]) if (existsSync4(join27(dir, "index.html"))) return dir;
|
|
6103
6045
|
return null;
|
|
6104
6046
|
}
|
|
6105
6047
|
async function cmdHubServe(values, positionals) {
|
|
@@ -6113,8 +6055,8 @@ async function cmdHubServe(values, positionals) {
|
|
|
6113
6055
|
if (problem) throw new UsageError(problem);
|
|
6114
6056
|
const port = Number(values.port ?? process.env.PORT ?? 8080);
|
|
6115
6057
|
if (!Number.isInteger(port) || port < 0 || port > 65535) throw new UsageError(`--port ${JSON.stringify(values.port ?? process.env.PORT)}: expected a port number`);
|
|
6116
|
-
const { openStore, storeLocation: where2 } = await import("./src-
|
|
6117
|
-
const path =
|
|
6058
|
+
const { openStore, storeLocation: where2 } = await import("./src-LUPO3O76.js");
|
|
6059
|
+
const path = resolve14(values.db ?? process.env.YOUI_HUB_DB ?? join27(process.env.XDG_DATA_HOME || join27(homedir3(), ".local/share"), "youiyoux/hub.db"));
|
|
6118
6060
|
const store = await openStore({ path });
|
|
6119
6061
|
const dist = builtHub();
|
|
6120
6062
|
const hub = await startOrgHub({ store, ...github ? { github } : { ingestToken: process.env[HUB_TOKEN_ENV] }, viewKey: process.env[VIEW_KEY_ENV], dist, host: values.host ?? "127.0.0.1", port });
|
|
@@ -6133,7 +6075,7 @@ async function cmdInit(values) {
|
|
|
6133
6075
|
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)");
|
|
6134
6076
|
const root = values.project ?? process.cwd();
|
|
6135
6077
|
const design = await designArg(values.design, root);
|
|
6136
|
-
const result = await initProject({ root, ...design, schemaDir:
|
|
6078
|
+
const result = await initProject({ root, ...design, schemaDir: join27(TOOL_ROOT, "schema"), ...values.system ? { system: values.system } : {}, ...values.components ? { componentsDir: values.components } : {}, force: values.force });
|
|
6137
6079
|
if (!values.json) {
|
|
6138
6080
|
print(`${style.ok("created")} ${result.file}`);
|
|
6139
6081
|
for (const note of result.notes) print(style.dim(` \xB7 ${note}`));
|
|
@@ -6143,28 +6085,28 @@ async function cmdInit(values) {
|
|
|
6143
6085
|
return cmdSync({ ...design.package ? rest : values, project: root });
|
|
6144
6086
|
}
|
|
6145
6087
|
async function cmdAdopt(values) {
|
|
6146
|
-
const root =
|
|
6147
|
-
if (await exists(
|
|
6088
|
+
const root = resolve14(values.project ?? process.cwd());
|
|
6089
|
+
if (await exists(join27(root, PROJECT_FILE))) throw new Error(`${root} already has ${PROJECT_FILE}: it follows a design system already (youiyoux sync updates it)`);
|
|
6148
6090
|
const plan = await planAdoption({ root, ...values.components ? { componentsDir: values.components } : {}, ...values.css ? { css: values.css } : {}, ...values.system ? { system: values.system } : {}, fork: values.fork });
|
|
6149
|
-
const taken = (await Promise.all(plan.files.map(async (f) => await exists(
|
|
6091
|
+
const taken = (await Promise.all(plan.files.map(async (f) => await exists(join27(root, f.path)) ? f.path : null))).filter((f) => f !== null);
|
|
6150
6092
|
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" : ""}`);
|
|
6151
6093
|
if (values["dry-run"]) {
|
|
6152
6094
|
if (values.json) json3(plan);
|
|
6153
6095
|
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"));
|
|
6154
6096
|
return 0;
|
|
6155
6097
|
}
|
|
6156
|
-
const stylesheet = plan.stylesheet ? await readFile11(
|
|
6098
|
+
const stylesheet = plan.stylesheet ? await readFile11(join27(root, plan.stylesheet.path), "utf8") : null;
|
|
6157
6099
|
try {
|
|
6158
|
-
for (const file of plan.files) await writeFileAtomic(
|
|
6159
|
-
if (plan.stylesheet) await writeFileAtomic(
|
|
6160
|
-
await initProject({ root, design: root, schemaDir:
|
|
6100
|
+
for (const file of plan.files) await writeFileAtomic(join27(root, file.path), file.content);
|
|
6101
|
+
if (plan.stylesheet) await writeFileAtomic(join27(root, plan.stylesheet.path), plan.stylesheet.content);
|
|
6102
|
+
await initProject({ root, design: root, schemaDir: join27(TOOL_ROOT, "schema"), system: plan.system.id, componentsDir: plan.componentsDir, outputs: { ...plan.outputs, targets: [...plan.outputs.targets], dark: [...plan.outputs.dark] }, tokenSources: plan.tokenSources });
|
|
6161
6103
|
await syncProject(await loadProject(root), { dryRun: true });
|
|
6162
6104
|
} catch (error) {
|
|
6163
|
-
for (const file of [...plan.files.map((f) => f.path), PROJECT_FILE]) await rm7(
|
|
6164
|
-
for (const folder of [...new Set(plan.files.map((f) => dirname13(f.path)))].sort((a, b) => b.length - a.length)) await rmdir3(
|
|
6165
|
-
await rmdir3(
|
|
6166
|
-
await rmdir3(
|
|
6167
|
-
if (plan.stylesheet && stylesheet !== null) await writeFileAtomic(
|
|
6105
|
+
for (const file of [...plan.files.map((f) => f.path), PROJECT_FILE]) await rm7(join27(root, file), { force: true });
|
|
6106
|
+
for (const folder of [...new Set(plan.files.map((f) => dirname13(f.path)))].sort((a, b) => b.length - a.length)) await rmdir3(join27(root, folder)).catch(() => void 0);
|
|
6107
|
+
await rmdir3(join27(root, "design/components")).catch(() => void 0);
|
|
6108
|
+
await rmdir3(join27(root, "design")).catch(() => void 0);
|
|
6109
|
+
if (plan.stylesheet && stylesheet !== null) await writeFileAtomic(join27(root, plan.stylesheet.path), stylesheet);
|
|
6168
6110
|
throw new Error(`adopt was undone, nothing kept: ${error instanceof Error ? error.message : String(error)}`);
|
|
6169
6111
|
}
|
|
6170
6112
|
if (!values.json) print([...adoptLines(plan), ""].join("\n"));
|
|
@@ -6233,31 +6175,31 @@ async function cmdUnlink(values) {
|
|
|
6233
6175
|
const root = values.project ?? process.cwd();
|
|
6234
6176
|
const linked = await linkedDesign(root);
|
|
6235
6177
|
if (linked !== null) await setLink(root, null);
|
|
6236
|
-
print(linked ? `${style.ok("unlinked")} ${
|
|
6178
|
+
print(linked ? `${style.ok("unlinked")} ${resolve14(root)} uses its config's source again` : `${resolve14(root)} was not linked`);
|
|
6237
6179
|
return 0;
|
|
6238
6180
|
}
|
|
6239
6181
|
async function designArg(value, root) {
|
|
6240
|
-
if (
|
|
6241
|
-
return { design: await designRootOf({ package: value },
|
|
6182
|
+
if (existsSync4(resolve14(value)) || !PACKAGE_NAME.test(value)) return { design: value };
|
|
6183
|
+
return { design: await designRootOf({ package: value }, join27(resolve14(root), PROJECT_FILE), root), package: value };
|
|
6242
6184
|
}
|
|
6243
6185
|
async function cmdBuild(values) {
|
|
6244
|
-
const root =
|
|
6186
|
+
const root = resolve14(values.design ?? process.cwd());
|
|
6245
6187
|
const system = getSystem(await loadDesignRepo(root), values.system);
|
|
6246
6188
|
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.`);
|
|
6247
6189
|
const output = OutputConfig.parse({ cssVarPrefix: values.prefix ?? "youi", targets: ["css-vars", "tailwind-v4", "ts", "react-native"] });
|
|
6248
6190
|
const started = performance.now();
|
|
6249
6191
|
const built = await buildTokens(root, system.config, output, { contracts: system.components.map((c) => c.contract) });
|
|
6250
|
-
const out =
|
|
6251
|
-
const boundary = values.out ? out :
|
|
6252
|
-
if (!within(boundary, out) || built.files.some((file) => !within(out,
|
|
6253
|
-
for (const file of built.files) await writeFileAtomic(
|
|
6192
|
+
const out = resolve14(values.out ?? join27(root, "build", system.config.id));
|
|
6193
|
+
const boundary = values.out ? out : join27(root, "build");
|
|
6194
|
+
if (!within(boundary, out) || built.files.some((file) => !within(out, join27(out, file.path)))) throw new Error(`Cannot build system ${JSON.stringify(system.config.id)}: an output path leaves the output directory.`);
|
|
6195
|
+
for (const file of built.files) await writeFileAtomic(join27(out, file.path), file.content);
|
|
6254
6196
|
if (values.json) json3({ out, files: built.files.map((f) => f.path), tokens: built.tokens.length });
|
|
6255
6197
|
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)})`)}`);
|
|
6256
6198
|
return 0;
|
|
6257
6199
|
}
|
|
6258
6200
|
async function cmdParity(values) {
|
|
6259
6201
|
if (!values.css) throw new UsageError("youiyoux parity --css <file> [--prefix p]");
|
|
6260
|
-
const root =
|
|
6202
|
+
const root = resolve14(values.design ?? process.cwd());
|
|
6261
6203
|
const system = getSystem(await loadDesignRepo(root), values.system);
|
|
6262
6204
|
const prefix = values.prefix ?? "youi";
|
|
6263
6205
|
const dark = { selector: values.dark ?? ':root[data-theme="dark"]' };
|
|
@@ -6275,16 +6217,16 @@ async function cmdParity(values) {
|
|
|
6275
6217
|
async function cmdSchema(values) {
|
|
6276
6218
|
const schemas = renderJsonSchemas();
|
|
6277
6219
|
if (values.check) {
|
|
6278
|
-
const dir =
|
|
6220
|
+
const dir = join27(values.design ? resolve14(values.design) : TOOL_ROOT, "schema");
|
|
6279
6221
|
const stale = [];
|
|
6280
|
-
for (const { file, content } of schemas) if (await readFile11(
|
|
6222
|
+
for (const { file, content } of schemas) if (await readFile11(join27(dir, file), "utf8").catch(() => null) !== content) stale.push(file);
|
|
6281
6223
|
if (values.json) json3({ dir, stale });
|
|
6282
6224
|
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>" : ""}`);
|
|
6283
6225
|
return stale.length === 0 ? 0 : 1;
|
|
6284
6226
|
}
|
|
6285
6227
|
if (values.write) {
|
|
6286
|
-
const root = values.design ?
|
|
6287
|
-
for (const { file, content } of schemas) await writeFileAtomic(
|
|
6228
|
+
const root = values.design ? resolve14(values.design) : TOOL_ROOT;
|
|
6229
|
+
for (const { file, content } of schemas) await writeFileAtomic(join27(root, "schema", file), content);
|
|
6288
6230
|
print(`${style.ok("wrote")} ${schemas.map((s) => s.file).join(", ")}`);
|
|
6289
6231
|
} else json3(Object.fromEntries(schemas.map((s) => [s.file, JSON.parse(s.content)])));
|
|
6290
6232
|
return 0;
|
|
@@ -6314,7 +6256,7 @@ async function cmdHooks(values, positionals) {
|
|
|
6314
6256
|
}
|
|
6315
6257
|
const p = await loadCheckProject(values.project ?? process.cwd(), loadOptions(values), !values.project);
|
|
6316
6258
|
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");
|
|
6317
|
-
const target = { ...hookTarget(values), project: p.root, ...configured(p) && p.configFile && p.configFile !==
|
|
6259
|
+
const target = { ...hookTarget(values), project: p.root, ...configured(p) && p.configFile && p.configFile !== join27(p.root, PROJECT_FILE) ? { config: p.configFile } : {}, ...values.root !== void 0 ? { root: p.root } : {} };
|
|
6318
6260
|
const all = !values.claude && !values.git && !values.ci;
|
|
6319
6261
|
const results = [];
|
|
6320
6262
|
if (values.claude || all) results.push({ kind: "Claude Code", ...await installClaudeHook(await repoRootOf(p.root), hookCommand(TOOL_ROOT, "claude", target)) });
|
|
@@ -6330,11 +6272,11 @@ async function cmdHooks(values, positionals) {
|
|
|
6330
6272
|
async function cmdAgents(values, positionals) {
|
|
6331
6273
|
const [action] = positionals;
|
|
6332
6274
|
if (action !== "install" && action !== "remove") throw new UsageError("youiyoux agents install|remove [--claude] [--codex] [--json]");
|
|
6333
|
-
const projectRoot =
|
|
6275
|
+
const projectRoot = resolve14(values.project ?? process.cwd());
|
|
6334
6276
|
const repoRoot = await repoRootOf(projectRoot);
|
|
6335
|
-
const target = { project: projectRoot, ...values.config ? { config:
|
|
6277
|
+
const target = { project: projectRoot, ...values.config ? { config: resolve14(values.config) } : {}, ...values.design ? { design: resolve14(values.design) } : {}, ...values.root !== void 0 ? { root: resolve14(values.root || ".") } : {} };
|
|
6336
6278
|
const server = mcpCommand(TOOL_ROOT, target);
|
|
6337
|
-
const system =
|
|
6279
|
+
const system = existsSync4(resolve14(values.config ?? join27(projectRoot, PROJECT_FILE))) ? await project(values) : null;
|
|
6338
6280
|
const claudeServer = system && system.root === repoRoot ? { command: "node", args: mcpArgs(system) } : relativeTo(repoRoot, server);
|
|
6339
6281
|
const both = !values.claude && !values.codex;
|
|
6340
6282
|
const results = [];
|
|
@@ -6442,8 +6384,8 @@ async function cmdUi(values) {
|
|
|
6442
6384
|
async function cmdDetect(values, positionals) {
|
|
6443
6385
|
const target = detectTarget(positionals);
|
|
6444
6386
|
if (!target) throw new UsageError("youiyoux detect <repo-path> or youiyoux detect <url\u2026> [--expose] (one repo, or one or more URLs; not both)");
|
|
6445
|
-
const { repoReport, siteReport, writeReport } = await import("./src-
|
|
6446
|
-
const out =
|
|
6387
|
+
const { repoReport, siteReport, writeReport } = await import("./src-7SHBAJEO.js");
|
|
6388
|
+
const out = resolve14(values.out ?? ".youi/detect");
|
|
6447
6389
|
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 } : {} });
|
|
6448
6390
|
const file = await writeReport(report, out);
|
|
6449
6391
|
if (values.json) json3(report);
|
|
@@ -6454,8 +6396,8 @@ async function cmdDetect(values, positionals) {
|
|
|
6454
6396
|
return 0;
|
|
6455
6397
|
}
|
|
6456
6398
|
async function cmdRender(values, positionals, io) {
|
|
6457
|
-
const root =
|
|
6458
|
-
const targets = positionals.map((t) =>
|
|
6399
|
+
const root = resolve14(values.root ?? values.project ?? process.cwd());
|
|
6400
|
+
const targets = positionals.map((t) => existsSync4(resolve14(t)) ? resolve14(t) : t);
|
|
6459
6401
|
try {
|
|
6460
6402
|
const report = await renderShots(root, targets, { ...values.base ? { base: values.base } : {}, ...process.env.YOUI_CHROMIUM ? { executablePath: process.env.YOUI_CHROMIUM } : {}, ...io.render });
|
|
6461
6403
|
if (values.json) json3({ ...report, next: shotsNext(report, (t) => `run youiyoux render${t ? ` ${t}` : ""} again`) });
|
|
@@ -6469,14 +6411,14 @@ async function cmdRender(values, positionals, io) {
|
|
|
6469
6411
|
}
|
|
6470
6412
|
}
|
|
6471
6413
|
async function product(values) {
|
|
6472
|
-
const project2 = await loadProject(
|
|
6473
|
-
return { project: project2, root: project2?.root ??
|
|
6414
|
+
const project2 = await loadProject(resolve14(values.project ?? process.cwd()), loadOptions(values)).catch(() => null);
|
|
6415
|
+
return { project: project2, root: project2?.root ?? resolve14(values.root ?? values.project ?? process.cwd()) };
|
|
6474
6416
|
}
|
|
6475
6417
|
async function cmdRequests(values, positionals) {
|
|
6476
6418
|
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>";
|
|
6477
6419
|
const [action, id, ...rest] = positionals;
|
|
6478
6420
|
if (rest.length > 0) throw new UsageError(usage);
|
|
6479
|
-
const { RequestStore, requestBrief } = await import("./src-
|
|
6421
|
+
const { RequestStore, requestBrief } = await import("./src-CCGTRT5J.js");
|
|
6480
6422
|
const { project: project2, root } = await product(values);
|
|
6481
6423
|
const store = new RequestStore(root, project2?.config.id ?? basename5(root));
|
|
6482
6424
|
const agent = { kind: "agent", name: "youiyoux CLI" };
|
|
@@ -6508,17 +6450,17 @@ async function cmdScreens(values, positionals, io) {
|
|
|
6508
6450
|
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>]";
|
|
6509
6451
|
if (!["capture", "login"].includes(positionals[0] ?? "") || positionals.length > 1 || !values.base) throw new UsageError(usage);
|
|
6510
6452
|
const { root } = await product(values);
|
|
6511
|
-
if (positionals[0] === "login") return screensLogin(values.base, values["storage-state"] ?
|
|
6512
|
-
const dir =
|
|
6513
|
-
if (!
|
|
6453
|
+
if (positionals[0] === "login") return screensLogin(values.base, values["storage-state"] ? resolve14(values["storage-state"]) : sessionFile(root), io);
|
|
6454
|
+
const dir = resolve14(values.out ?? join27(root, ".youi/screens"));
|
|
6455
|
+
if (!existsSync4(join27(dir, "screens.json"))) {
|
|
6514
6456
|
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":"/"}]}
|
|
6515
6457
|
`);
|
|
6516
6458
|
return 1;
|
|
6517
6459
|
}
|
|
6518
|
-
const session = chosenSession(root, values["storage-state"] ?
|
|
6460
|
+
const session = chosenSession(root, values["storage-state"] ? resolve14(values["storage-state"]) : void 0);
|
|
6519
6461
|
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`)}
|
|
6520
6462
|
`);
|
|
6521
|
-
const { launchBrowser } = await import("./src-
|
|
6463
|
+
const { launchBrowser } = await import("./src-7SHBAJEO.js");
|
|
6522
6464
|
const browser = await launchBrowser(process.env.YOUI_CHROMIUM, { purpose: { what: "youiyoux screens capture", command: "youiyoux screens capture" } });
|
|
6523
6465
|
try {
|
|
6524
6466
|
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)}
|
|
@@ -6575,7 +6517,7 @@ async function cmdReport(values, positionals, io) {
|
|
|
6575
6517
|
return result.code;
|
|
6576
6518
|
}
|
|
6577
6519
|
async function cmdMcp(values) {
|
|
6578
|
-
const { startStdioServer } = await import("./src-
|
|
6520
|
+
const { startStdioServer } = await import("./src-3LEBH7E3.js");
|
|
6579
6521
|
await startStdioServer({ projectRoot: values.project ?? process.cwd(), ...loadOptions(values), ...values.cache ? { discoverCache: values.cache } : {} });
|
|
6580
6522
|
return -1;
|
|
6581
6523
|
}
|
|
@@ -6586,7 +6528,7 @@ function positiveInt(value, flag) {
|
|
|
6586
6528
|
return n;
|
|
6587
6529
|
}
|
|
6588
6530
|
async function cmdDiscover(values, positionals, io) {
|
|
6589
|
-
const cacheDir =
|
|
6531
|
+
const cacheDir = resolve14(discoverCacheDir(values.cache));
|
|
6590
6532
|
const { path, home } = indexOf(values);
|
|
6591
6533
|
const catalog = () => readCatalog(cacheDir, path);
|
|
6592
6534
|
const [action, ...rest] = positionals;
|