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
|
@@ -2,10 +2,10 @@ import { createRequire as __youiRequire } from "node:module"; import { dirname a
|
|
|
2
2
|
|
|
3
3
|
// src/hub-packages.js
|
|
4
4
|
var PACKAGES = {
|
|
5
|
-
core: () => import("./src-
|
|
6
|
-
scanner: () => import("./src-
|
|
7
|
-
discover: () => import("./src-
|
|
8
|
-
tokens: () => import("./src-
|
|
5
|
+
core: () => import("./src-4BOFDAZD.js"),
|
|
6
|
+
scanner: () => import("./src-6JO73FOS.js"),
|
|
7
|
+
discover: () => import("./src-7LETTRRF.js"),
|
|
8
|
+
tokens: () => import("./src-WMGLZKYK.js")
|
|
9
9
|
};
|
|
10
10
|
var loadPackage = (name) => PACKAGES[name]();
|
|
11
11
|
|
|
@@ -0,0 +1,110 @@
|
|
|
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
|
+
loadProject
|
|
4
|
+
} from "./chunk-HII2I2PI.js";
|
|
5
|
+
import {
|
|
6
|
+
shortHash
|
|
7
|
+
} from "./chunk-S7UN5KQK.js";
|
|
8
|
+
|
|
9
|
+
// ../cli/src/ui.ts
|
|
10
|
+
import * as util from "node:util";
|
|
11
|
+
var styleText2 = util.styleText ?? ((format, text) => [format].flat().reduceRight((inner, name) => {
|
|
12
|
+
const [open, close] = util.inspect.colors[name] ?? [0, 0];
|
|
13
|
+
return `\x1B[${open}m${inner}\x1B[${close}m`;
|
|
14
|
+
}, text));
|
|
15
|
+
var enabled = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR && process.env.TERM !== "dumb";
|
|
16
|
+
var paint = (format) => (text) => enabled ? styleText2(format, String(text), { validateStream: false }) : String(text);
|
|
17
|
+
var style = {
|
|
18
|
+
bold: paint("bold"),
|
|
19
|
+
dim: paint("dim"),
|
|
20
|
+
error: paint("red"),
|
|
21
|
+
warn: paint("yellow"),
|
|
22
|
+
ok: paint("green"),
|
|
23
|
+
live: paint("blue"),
|
|
24
|
+
accent: paint(["bold", "white"])
|
|
25
|
+
};
|
|
26
|
+
function plural(count, word, many = `${word}s`) {
|
|
27
|
+
return `${count} ${count === 1 ? word : many}`;
|
|
28
|
+
}
|
|
29
|
+
var ANSI = /\u001b\[[0-9;]*m/g;
|
|
30
|
+
function visibleLength(text) {
|
|
31
|
+
return text.replace(ANSI, "").length;
|
|
32
|
+
}
|
|
33
|
+
function padEnd(text, width) {
|
|
34
|
+
return text + " ".repeat(Math.max(0, width - visibleLength(text)));
|
|
35
|
+
}
|
|
36
|
+
function padStart(text, width) {
|
|
37
|
+
return " ".repeat(Math.max(0, width - visibleLength(text))) + text;
|
|
38
|
+
}
|
|
39
|
+
function truncate(text, width) {
|
|
40
|
+
return text.length <= width ? text : `${text.slice(0, Math.max(0, width - 1))}\u2026`;
|
|
41
|
+
}
|
|
42
|
+
function bar(value, max, width = 24) {
|
|
43
|
+
const cells = max === 0 ? 0 : Math.max(value > 0 ? 1 : 0, Math.round(value / max * width));
|
|
44
|
+
return style.dim("\u2588".repeat(cells));
|
|
45
|
+
}
|
|
46
|
+
function rule(width = 64) {
|
|
47
|
+
return style.dim("\u2500".repeat(width));
|
|
48
|
+
}
|
|
49
|
+
function ms(value) {
|
|
50
|
+
return value < 1e3 ? `${Math.round(value)} ms` : `${(value / 1e3).toFixed(2)} s`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ../cli/src/editor.ts
|
|
54
|
+
import { randomBytes } from "node:crypto";
|
|
55
|
+
import { existsSync } from "node:fs";
|
|
56
|
+
import { homedir, userInfo } from "node:os";
|
|
57
|
+
import { join, resolve } from "node:path";
|
|
58
|
+
async function swapImpact(candidate, family) {
|
|
59
|
+
try {
|
|
60
|
+
const { discoverIndexPath, sharedStore } = await import("./src-7LETTRRF.js");
|
|
61
|
+
const path = discoverIndexPath();
|
|
62
|
+
if (!process.env.DATABASE_URL && !existsSync(path)) return null;
|
|
63
|
+
const impact = await (await sharedStore(path, process.env, { readOnly: true })).swapImpact(candidate, family);
|
|
64
|
+
return impact && !("choices" in impact) ? { looks: impact.looks, files: impact.files.length, routes: impact.routes.length, listed: impact.listed } : null;
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function libraryLicence(id) {
|
|
70
|
+
try {
|
|
71
|
+
const { discoverCacheDir, findListing } = await import("./src-7LETTRRF.js");
|
|
72
|
+
const { entry } = await findListing(discoverCacheDir(void 0, process.env), id);
|
|
73
|
+
return entry.id === id ? entry.license : null;
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function workflowStateDir(project, state) {
|
|
79
|
+
return resolve(state ?? join(homedir(), ".youi", "workflow", shortHash(`${project.repo.root}\0${project.root}`)));
|
|
80
|
+
}
|
|
81
|
+
async function ingest(link) {
|
|
82
|
+
const { readLink } = await import("./ingest-OF4Z33L2.js");
|
|
83
|
+
return readLink(link, { allowLocal: false });
|
|
84
|
+
}
|
|
85
|
+
async function startRuleEditor(options) {
|
|
86
|
+
const { FileStore, RuleWorkflow, serveWorkflow } = await import("./src-CCGTRT5J.js");
|
|
87
|
+
const projectRoot = resolve(options.project);
|
|
88
|
+
const load = { ...options.config ? { configPath: resolve(options.config) } : {}, ...options.design ? { designRoot: resolve(options.design) } : {}, ...options.root ? { productRoot: resolve(options.root) } : {} };
|
|
89
|
+
const project = await loadProject(projectRoot, load);
|
|
90
|
+
const stateDir = workflowStateDir(project, options.state);
|
|
91
|
+
const workflow = new RuleWorkflow({ projectRoot, store: new FileStore(stateDir), swapImpact, libraryLicence, ingest, ...load });
|
|
92
|
+
const actor = { kind: "person", name: userInfo().username };
|
|
93
|
+
const info = await workflow.info(actor);
|
|
94
|
+
const sessionKey = randomBytes(24).toString("base64url");
|
|
95
|
+
const service = await serveWorkflow({ workflow, actor, sessionKey, port: 0 });
|
|
96
|
+
return { url: service.url, sessionKey, stateDir, info, close: () => service.close() };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export {
|
|
100
|
+
style,
|
|
101
|
+
plural,
|
|
102
|
+
padEnd,
|
|
103
|
+
padStart,
|
|
104
|
+
truncate,
|
|
105
|
+
bar,
|
|
106
|
+
rule,
|
|
107
|
+
ms,
|
|
108
|
+
workflowStateDir,
|
|
109
|
+
startRuleEditor
|
|
110
|
+
};
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
sameColor,
|
|
19
19
|
splitTopLevel,
|
|
20
20
|
tailwindTheme
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-HIXGUALJ.js";
|
|
22
22
|
import {
|
|
23
23
|
AST_GREP_LANGUAGES,
|
|
24
24
|
BUILT_IN_CHECKS,
|
|
@@ -51,7 +51,7 @@ import {
|
|
|
51
51
|
toPosix,
|
|
52
52
|
unifiedDiff,
|
|
53
53
|
writeFileAtomic
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-S7UN5KQK.js";
|
|
55
55
|
|
|
56
56
|
// ../scanner/src/parse.ts
|
|
57
57
|
import { Lang, parseAsync } from "@ast-grep/napi";
|
|
@@ -7928,7 +7928,7 @@ var Eyes = class {
|
|
|
7928
7928
|
}
|
|
7929
7929
|
async open() {
|
|
7930
7930
|
if (this.browser) return this.browser;
|
|
7931
|
-
const { launchBrowser } = await import("./src-
|
|
7931
|
+
const { launchBrowser } = await import("./src-7SHBAJEO.js");
|
|
7932
7932
|
try {
|
|
7933
7933
|
this.browser = await launchBrowser(this.options.executablePath, { purpose: { what: "youiyoux render", command: "youiyoux render" }, ...this.options.download === false ? { download: false } : {}, ...this.options.log ? { log: this.options.log } : {} });
|
|
7934
7934
|
} catch (error) {
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
loadPackage,
|
|
5
5
|
readTryIndex,
|
|
6
6
|
send
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-F3KCL226.js";
|
|
8
8
|
import {
|
|
9
9
|
writeFileAtomic
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-S7UN5KQK.js";
|
|
11
11
|
|
|
12
12
|
// ../../apps/web/scripts/discover-thumbs.ts
|
|
13
13
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
scanProject,
|
|
10
10
|
screenSlug,
|
|
11
11
|
tokenImpact
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-HII2I2PI.js";
|
|
13
13
|
import {
|
|
14
14
|
buildTokens,
|
|
15
15
|
contrastText,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
resolverLayout,
|
|
19
19
|
ringOffset,
|
|
20
20
|
systemPairs
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-HIXGUALJ.js";
|
|
22
22
|
import {
|
|
23
23
|
BUILT_IN_CHECKS,
|
|
24
24
|
COMPONENT_STATES,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
toPosix,
|
|
46
46
|
tokenValueProblems,
|
|
47
47
|
writeFileAtomic
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-S7UN5KQK.js";
|
|
49
49
|
import {
|
|
50
50
|
__toESM
|
|
51
51
|
} from "./chunk-WNTS7ZO4.js";
|
|
@@ -844,12 +844,15 @@ var TokenEditInput = external_exports.object({ path: external_exports.string().m
|
|
|
844
844
|
var StateEditInput = external_exports.object({ component: ElementId, state: external_exports.enum(COMPONENT_STATES), role: external_exports.string().min(1).max(100), token: ElementId });
|
|
845
845
|
var StyleContentInput = external_exports.object({ title: external_exports.string().max(200), tokens: external_exports.array(TokenEditInput).max(500), states: external_exports.array(StateEditInput).max(200) });
|
|
846
846
|
var LibraryContentInput = external_exports.object({ entry: LibraryEntry, request: external_exports.enum(["save", "adopt"]), reason: external_exports.string().max(2e3), swapsWith: external_exports.array(external_exports.string().min(1).max(200)).max(50) });
|
|
847
|
+
var IngestCreateInput = external_exports.object({ kind: external_exports.literal("ingest"), link: external_exports.string().min(1).max(2e3) });
|
|
848
|
+
var IngestKeepInput = external_exports.object({ keep: external_exports.array(external_exports.string().min(1).max(300)).max(1e3) }).strict();
|
|
847
849
|
var CreateInput = external_exports.union([
|
|
848
850
|
external_exports.object({ kind: external_exports.literal("style"), content: StyleContentInput.optional() }),
|
|
849
851
|
external_exports.object({ kind: external_exports.literal("library"), content: LibraryContentInput }),
|
|
852
|
+
IngestCreateInput,
|
|
850
853
|
external_exports.discriminatedUnion("mode", [external_exports.object({ kind: external_exports.literal("rule").optional(), mode: external_exports.literal("edit"), ruleId: ElementId }), external_exports.object({ kind: external_exports.literal("rule").optional(), mode: external_exports.literal("create") })])
|
|
851
854
|
]);
|
|
852
|
-
var SaveInput = external_exports.object({ revision: external_exports.number().int().positive(), content: external_exports.union([DraftContentInput, StyleContentInput, LibraryContentInput]) });
|
|
855
|
+
var SaveInput = external_exports.object({ revision: external_exports.number().int().positive(), content: external_exports.union([DraftContentInput, StyleContentInput, LibraryContentInput, IngestKeepInput]) });
|
|
853
856
|
var RequestInput = external_exports.object({ kind: external_exports.enum(["comment", "change"]), body: external_exports.string().min(1).max(4e3), target: RequestTarget });
|
|
854
857
|
var ReplyInput = external_exports.object({ body: external_exports.string().min(1).max(4e3) });
|
|
855
858
|
var StatusInput = external_exports.object({ status: external_exports.enum(REQUEST_STATUSES), body: external_exports.string().max(4e3).optional() });
|
|
@@ -921,6 +924,7 @@ async function api(req, res, path, options) {
|
|
|
921
924
|
if (path === "/api/drafts" && method === "POST") {
|
|
922
925
|
const input = parse2(CreateInput, await readJson(req));
|
|
923
926
|
if ("kind" in input && input.kind === "library") return send(res, 201, await workflow.create(actor, { kind: "library", content: input.content }));
|
|
927
|
+
if ("kind" in input && input.kind === "ingest") return send(res, 201, await workflow.create(actor, { kind: "ingest", link: input.link }));
|
|
924
928
|
return send(res, 201, await workflow.create(actor, "kind" in input && input.kind === "style" ? { kind: "style", ...input.content ? { content: styleContent(input.content) } : {} } : input));
|
|
925
929
|
}
|
|
926
930
|
if (path === "/api/requests" && method === "GET") return send(res, 200, await (await workflow.requests()).list());
|
|
@@ -1051,6 +1055,55 @@ function describeLibrary(content) {
|
|
|
1051
1055
|
return content.request === "adopt" ? `request adoption of ${name}${swaps} (licence ${licenceOf(content)})` : `save ${name} to the Library${swaps}`;
|
|
1052
1056
|
}
|
|
1053
1057
|
|
|
1058
|
+
// ../workflow/src/ingest-drafts.ts
|
|
1059
|
+
function normalizeIngestContent(content) {
|
|
1060
|
+
const keep = new Set(content.keep);
|
|
1061
|
+
return { reading: content.reading, keep: content.reading.entries.map((e) => e.id).filter((id) => keep.has(id)) };
|
|
1062
|
+
}
|
|
1063
|
+
function ingestDigest(content) {
|
|
1064
|
+
return sha256(stableStringify(normalizeIngestContent(content)));
|
|
1065
|
+
}
|
|
1066
|
+
var keptEntries = (content) => {
|
|
1067
|
+
const keep = new Set(content.keep);
|
|
1068
|
+
return content.reading.entries.filter((e) => keep.has(e.id));
|
|
1069
|
+
};
|
|
1070
|
+
function validateIngestContent(content) {
|
|
1071
|
+
const problems = [];
|
|
1072
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1073
|
+
const sources = new Set(content.reading.entries.map((e) => e.source.name));
|
|
1074
|
+
if (sources.size > 1) problems.push(`items come from ${sources.size} sources; one link is one source`);
|
|
1075
|
+
for (const entry of content.reading.entries) {
|
|
1076
|
+
const parsed = LibraryEntry.safeParse(entry);
|
|
1077
|
+
if (!parsed.success) problems.push(`${entry.id ?? "an item"}: ${parsed.error.issues.slice(0, 2).map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`);
|
|
1078
|
+
if (ids.has(entry.id)) problems.push(`${entry.id} is listed twice`);
|
|
1079
|
+
ids.add(entry.id);
|
|
1080
|
+
if (entry.stage !== "library") problems.push(`${entry.id}: an ingested item is a reference (stage library), not ${entry.stage}`);
|
|
1081
|
+
try {
|
|
1082
|
+
libraryPath(entry.id);
|
|
1083
|
+
} catch (error) {
|
|
1084
|
+
problems.push(error instanceof Error ? error.message : String(error));
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
const unknown = content.keep.filter((id) => !ids.has(id));
|
|
1088
|
+
if (unknown.length > 0) problems.push(`keep: ${unknown.join(", ")} ${unknown.length === 1 ? "is" : "are"} not in this reading`);
|
|
1089
|
+
if (keptEntries(content).length === 0) problems.push("keep at least one item, or discard the draft");
|
|
1090
|
+
return problems;
|
|
1091
|
+
}
|
|
1092
|
+
function describeIngest(content) {
|
|
1093
|
+
const kept = keptEntries(content).length;
|
|
1094
|
+
const all = content.reading.entries.length;
|
|
1095
|
+
return `ingest ${kept === all ? `${all}` : `${kept} of ${all}`} item${all === 1 ? "" : "s"} from ${content.reading.source.name} into the Library`;
|
|
1096
|
+
}
|
|
1097
|
+
function ingestFiles(content, existing) {
|
|
1098
|
+
return Object.fromEntries(keptEntries(content).map((entry) => {
|
|
1099
|
+
const path = libraryPath(entry.id);
|
|
1100
|
+
return [path, renderLibraryEntry({ entry, request: "save", reason: "", swapsWith: [] }, existing(path))];
|
|
1101
|
+
}));
|
|
1102
|
+
}
|
|
1103
|
+
function ingestSlug(content) {
|
|
1104
|
+
return content.reading.source.name.toLowerCase().replace(/[^a-z0-9.-]+/g, "-").replace(/\.+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "") || "link";
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1054
1107
|
// ../workflow/src/preview.ts
|
|
1055
1108
|
var MAX_FINDINGS = 400;
|
|
1056
1109
|
var keyOf = (v) => `${v.file}:${v.line}:${v.column}:${v.text}`;
|
|
@@ -1423,6 +1476,12 @@ var WORKFLOW_VERSION = "0.1.0";
|
|
|
1423
1476
|
var MAX_PLACES = 200;
|
|
1424
1477
|
function previewSummary(draft) {
|
|
1425
1478
|
if (draft.kind === "rule") return draft.preview ? `flags ${draft.preview.flagged} place(s)` : "no preview";
|
|
1479
|
+
if (draft.kind === "ingest") {
|
|
1480
|
+
const q = draft.preview;
|
|
1481
|
+
if (!q) return "no preview";
|
|
1482
|
+
const edits = q.files.filter((f) => f.exists).length;
|
|
1483
|
+
return `writes ${q.files.length} Library item(s)${edits ? ` (${edits} already there, edited)` : ""}${q.dropped ? `, ${q.dropped} dropped` : ""}, licence ${q.license}`;
|
|
1484
|
+
}
|
|
1426
1485
|
if (draft.kind === "library") {
|
|
1427
1486
|
const q = draft.preview;
|
|
1428
1487
|
if (!q) return "no preview";
|
|
@@ -1520,6 +1579,7 @@ var RuleWorkflow = class {
|
|
|
1520
1579
|
async problems(draft, current) {
|
|
1521
1580
|
if (draft.kind === "style") return validateStyleContent(draft.content, await this.styleContext(current));
|
|
1522
1581
|
if (draft.kind === "library") return validateLibraryContent(draft.content, { componentIds: new Set(current.project.system.components.map((c) => c.contract.id)) });
|
|
1582
|
+
if (draft.kind === "ingest") return validateIngestContent(draft.content);
|
|
1523
1583
|
return validateContent(draft.content, {
|
|
1524
1584
|
mode: draft.mode,
|
|
1525
1585
|
ruleId: draft.ruleId,
|
|
@@ -1603,7 +1663,7 @@ var RuleWorkflow = class {
|
|
|
1603
1663
|
checks: this.execution.supportedChecks(),
|
|
1604
1664
|
executor: this.execution.name,
|
|
1605
1665
|
components: current.project.system.components.map((c) => ({ id: c.contract.id, name: c.contract.name })),
|
|
1606
|
-
kinds: ["rule", "style", "library"],
|
|
1666
|
+
kinds: ["rule", "style", "library", ...this.options.ingest ? ["ingest"] : []],
|
|
1607
1667
|
limits: [
|
|
1608
1668
|
`One design repository and one project (${current.project.config.id}).`,
|
|
1609
1669
|
`Approved changes become a local review branch in the design repository; nothing is pushed or merged for you.`,
|
|
@@ -1655,6 +1715,7 @@ var RuleWorkflow = class {
|
|
|
1655
1715
|
const current = await this.current();
|
|
1656
1716
|
if (input.kind === "style") return this.createStyle(actor, current, input.content);
|
|
1657
1717
|
if (input.kind === "library") return this.createLibrary(actor, current, input.content);
|
|
1718
|
+
if (input.kind === "ingest") return this.createIngest(actor, current, input.link);
|
|
1658
1719
|
let content;
|
|
1659
1720
|
let ruleId;
|
|
1660
1721
|
const files = {};
|
|
@@ -1749,6 +1810,43 @@ var RuleWorkflow = class {
|
|
|
1749
1810
|
await this.options.store.put(draft);
|
|
1750
1811
|
return await this.view(draft, current);
|
|
1751
1812
|
}
|
|
1813
|
+
/**
|
|
1814
|
+
* An ingest draft starts from what this service reads at the link, every item kept, bound to the
|
|
1815
|
+
* Library files the items would write. A link that cannot be read is said, and no draft exists.
|
|
1816
|
+
*/
|
|
1817
|
+
async createIngest(actor, current, link) {
|
|
1818
|
+
if (!this.options.ingest) throw new WorkflowError("invalid", "this service cannot read links: run youiyoux library ingest <link> --draft");
|
|
1819
|
+
const reading = await this.options.ingest(link).catch((error) => {
|
|
1820
|
+
throw new WorkflowError("invalid", error instanceof Error ? error.message : String(error));
|
|
1821
|
+
});
|
|
1822
|
+
const content = normalizeIngestContent({ reading, keep: reading.entries.map((e) => e.id) });
|
|
1823
|
+
const problems = validateIngestContent(content);
|
|
1824
|
+
if (problems.length > 0) throw new WorkflowError("invalid", `${link} was read, but not into items the Library takes`, problems);
|
|
1825
|
+
const files = {};
|
|
1826
|
+
for (const entry of reading.entries) {
|
|
1827
|
+
const path = libraryPath(entry.id);
|
|
1828
|
+
files[path] = await current.files.digest(current.tip, path);
|
|
1829
|
+
}
|
|
1830
|
+
const at = this.now();
|
|
1831
|
+
const draft = {
|
|
1832
|
+
id: this.id("d"),
|
|
1833
|
+
kind: "ingest",
|
|
1834
|
+
mode: "create",
|
|
1835
|
+
createdAt: at,
|
|
1836
|
+
updatedAt: at,
|
|
1837
|
+
revision: 1,
|
|
1838
|
+
digest: ingestDigest(content),
|
|
1839
|
+
content,
|
|
1840
|
+
base: { branch: current.branch, commit: current.tip, files },
|
|
1841
|
+
preview: null,
|
|
1842
|
+
approval: null,
|
|
1843
|
+
handoff: null,
|
|
1844
|
+
discarded: false,
|
|
1845
|
+
events: [this.event(actor, "created", `${capitalized(describeIngest(content))}: read from ${reading.link}, from ${current.branch}@${current.tip.slice(0, 7)}.`)]
|
|
1846
|
+
};
|
|
1847
|
+
await this.options.store.put(draft);
|
|
1848
|
+
return await this.view(draft, current);
|
|
1849
|
+
}
|
|
1752
1850
|
/**
|
|
1753
1851
|
* The draft with the licence the local Discover index lists for its id, whatever the client
|
|
1754
1852
|
* sent: `unknown` when the index does not list it. With no index, a save keeps what was sent
|
|
@@ -1770,8 +1868,10 @@ var RuleWorkflow = class {
|
|
|
1770
1868
|
if (input.revision !== draft.revision) throw new WorkflowError("conflict", `draft ${id} is at revision ${draft.revision}, not ${input.revision}: it was saved elsewhere. Reload it before saving.`);
|
|
1771
1869
|
const isStyle = "tokens" in input.content;
|
|
1772
1870
|
const isLibrary = "entry" in input.content;
|
|
1773
|
-
|
|
1871
|
+
const isIngest = "keep" in input.content;
|
|
1872
|
+
if (isStyle !== (draft.kind === "style") || isLibrary !== (draft.kind === "library") || isIngest !== (draft.kind === "ingest")) throw new WorkflowError("bad-request", `draft ${id} is a ${draft.kind} draft; send ${draft.kind === "ingest" ? "the items to keep ({ keep: [ids] })" : `${draft.kind} content`}`);
|
|
1774
1873
|
if (draft.kind === "library") return this.saveLibrary(actor, draft, input.revision, input.content);
|
|
1874
|
+
if (draft.kind === "ingest") return this.saveIngest(actor, draft, input.revision, input.content.keep);
|
|
1775
1875
|
const current = await this.current();
|
|
1776
1876
|
const content = isStyle ? normalizeStyleContent(input.content) : input.content;
|
|
1777
1877
|
const digest = isStyle ? styleDigest(content) : contentDigest(content);
|
|
@@ -1784,6 +1884,21 @@ var RuleWorkflow = class {
|
|
|
1784
1884
|
return this.view(next, current);
|
|
1785
1885
|
});
|
|
1786
1886
|
}
|
|
1887
|
+
/** Only which items are kept changes: the reading is what the service read, and stays so. */
|
|
1888
|
+
async saveIngest(actor, draft, revision, keep) {
|
|
1889
|
+
const current = await this.current();
|
|
1890
|
+
const known = new Set(draft.content.reading.entries.map((e) => e.id));
|
|
1891
|
+
const unknown = keep.filter((id) => !known.has(id));
|
|
1892
|
+
if (unknown.length > 0) throw new WorkflowError("invalid", `${unknown.join(", ")} ${unknown.length === 1 ? "is" : "are"} not in what ${draft.content.reading.source.name} held`);
|
|
1893
|
+
const content = normalizeIngestContent({ reading: draft.content.reading, keep });
|
|
1894
|
+
const digest = ingestDigest(content);
|
|
1895
|
+
if (digest === draft.digest) return this.refreshed(draft, current);
|
|
1896
|
+
const events = [...draft.events, this.event(actor, "saved", `Revision ${revision + 1}: ${describeIngest(content)}.`)];
|
|
1897
|
+
if (draft.approval) events.push(this.event(actor, "approval-invalidated", "Approval withdrawn: the draft changed."));
|
|
1898
|
+
const next = { ...draft, revision: draft.revision + 1, digest, content, approval: null, updatedAt: this.now(), events };
|
|
1899
|
+
await this.options.store.put(next);
|
|
1900
|
+
return this.view(next, current);
|
|
1901
|
+
}
|
|
1787
1902
|
async saveLibrary(actor, draft, revision, input) {
|
|
1788
1903
|
const current = await this.current();
|
|
1789
1904
|
const content = await this.indexedLicence(normalizeLibraryContent(input));
|
|
@@ -1805,6 +1920,7 @@ var RuleWorkflow = class {
|
|
|
1805
1920
|
this.guard(actor, "preview", draft);
|
|
1806
1921
|
if (draft.kind === "style") return this.previewStyle(actor, draft);
|
|
1807
1922
|
if (draft.kind === "library") return this.previewLibrary(actor, draft);
|
|
1923
|
+
if (draft.kind === "ingest") return this.previewIngest(actor, draft);
|
|
1808
1924
|
const before = await this.current();
|
|
1809
1925
|
const problems = await this.problems(draft, before);
|
|
1810
1926
|
const { rule } = toRuleSpec(draft.content.rule);
|
|
@@ -1872,6 +1988,36 @@ var RuleWorkflow = class {
|
|
|
1872
1988
|
await this.options.store.put(next);
|
|
1873
1989
|
return this.refreshed(next, after);
|
|
1874
1990
|
}
|
|
1991
|
+
/** An ingest draft's preview: each kept item's Library file, new or an edit, and what the items are not. */
|
|
1992
|
+
async previewIngest(actor, draft) {
|
|
1993
|
+
const before = await this.current();
|
|
1994
|
+
const problems = await this.problems(draft, before);
|
|
1995
|
+
if (problems.length > 0) throw new WorkflowError("invalid", "fix the draft before previewing it", problems);
|
|
1996
|
+
const started = performance.now();
|
|
1997
|
+
const files = [];
|
|
1998
|
+
for (const entry of keptEntries(draft.content)) {
|
|
1999
|
+
const file = libraryPath(entry.id);
|
|
2000
|
+
files.push({ id: entry.id, file, exists: await before.files.read(before.tip, file) !== null });
|
|
2001
|
+
}
|
|
2002
|
+
const after = await this.unchangedSince(before);
|
|
2003
|
+
const { reading } = draft.content;
|
|
2004
|
+
const license = reading.license === "unknown" ? "unknown" : reading.license.spdx;
|
|
2005
|
+
const preview = {
|
|
2006
|
+
...this.previewHead(draft, before, started),
|
|
2007
|
+
files,
|
|
2008
|
+
dropped: reading.entries.length - files.length,
|
|
2009
|
+
license,
|
|
2010
|
+
limits: [
|
|
2011
|
+
"Nothing is installed and nothing joins the System: approving writes the kept items to the Library as references, each to be requested for adoption on its own.",
|
|
2012
|
+
...license === "unknown" ? [`${reading.source.name}'s licence is unknown: its items can be kept as references, not adopted, until a licence is found.`] : [],
|
|
2013
|
+
...files.some((f) => f.exists) ? ["Items already in the Library are rewritten with what this link holds now."] : [],
|
|
2014
|
+
...reading.skipped.length > 0 ? [`${reading.skipped.length} thing(s) at the link were not read as items; the draft lists them.`] : []
|
|
2015
|
+
]
|
|
2016
|
+
};
|
|
2017
|
+
const next = { ...draft, preview, updatedAt: this.now(), events: [...draft.events, this.event(actor, "previewed", `${capitalized(previewSummary({ ...draft, preview }))}.`)] };
|
|
2018
|
+
await this.options.store.put(next);
|
|
2019
|
+
return this.refreshed(next, after);
|
|
2020
|
+
}
|
|
1875
2021
|
/** Build the tokens as published and as drafted, and trace every changed value through one fresh scan. */
|
|
1876
2022
|
async previewStyle(actor, draft) {
|
|
1877
2023
|
const before = await this.current();
|
|
@@ -1957,7 +2103,7 @@ var RuleWorkflow = class {
|
|
|
1957
2103
|
const current = await this.current();
|
|
1958
2104
|
const view = await this.refreshed(draft, current);
|
|
1959
2105
|
if (!view.canHandoff) throw new WorkflowError("stale", "only a current approval can be handed off", [...view.problems, ...view.baseStale, ...view.approval ? [] : ["Approve the draft first (an approval is withdrawn when the draft, the design repository or the project changes)."]]);
|
|
1960
|
-
const { files, branch, message } = draft.kind === "style" ? await this.styleChange(draft, view, current) : draft.kind === "library" ? await this.libraryChange(draft, view, current) : await this.ruleChange(draft, view, current);
|
|
2106
|
+
const { files, branch, message } = draft.kind === "style" ? await this.styleChange(draft, view, current) : draft.kind === "library" ? await this.libraryChange(draft, view, current) : draft.kind === "ingest" ? await this.ingestChange(draft, view, current) : await this.ruleChange(draft, view, current);
|
|
1961
2107
|
if (Object.keys(files).length === 0) throw new WorkflowError("invalid", "this draft changes nothing in the design repository");
|
|
1962
2108
|
const created = await createReviewBranch(current.repo.top, {
|
|
1963
2109
|
base: draft.base.commit,
|
|
@@ -2050,6 +2196,25 @@ var RuleWorkflow = class {
|
|
|
2050
2196
|
].join("\n");
|
|
2051
2197
|
return { files: text === existing ? {} : { [path]: text }, branch: `youi/library/${librarySlug(draft.content)}-${draft.id.slice(2, 8)}`, message };
|
|
2052
2198
|
}
|
|
2199
|
+
/** What an ingest draft's review branch carries: one Library file per kept item. */
|
|
2200
|
+
async ingestChange(draft, view, current) {
|
|
2201
|
+
const existing = /* @__PURE__ */ new Map();
|
|
2202
|
+
for (const entry of keptEntries(draft.content)) existing.set(libraryPath(entry.id), await current.files.read(draft.base.commit, libraryPath(entry.id)));
|
|
2203
|
+
const all = ingestFiles(draft.content, (path) => existing.get(path) ?? null);
|
|
2204
|
+
const files = Object.fromEntries(Object.entries(all).filter(([path, text]) => text !== existing.get(path)));
|
|
2205
|
+
const { reading } = draft.content;
|
|
2206
|
+
const approval = view.approval;
|
|
2207
|
+
const message = [
|
|
2208
|
+
`library: ${describeIngest(draft.content)}`,
|
|
2209
|
+
"",
|
|
2210
|
+
`Read from ${reading.link} at ${reading.fetchedAt}; licence ${view.preview.license}.`,
|
|
2211
|
+
...keptEntries(draft.content).map((e) => `- ${e.id}: ${e.name}`),
|
|
2212
|
+
"",
|
|
2213
|
+
`Ingest draft ${draft.id} revision ${draft.revision}.`,
|
|
2214
|
+
`Approved by ${approval.by.name} at ${approval.at}.`
|
|
2215
|
+
].join("\n");
|
|
2216
|
+
return { files, branch: `youi/library/ingest-${ingestSlug(draft.content)}-${draft.id.slice(2, 8)}`, message };
|
|
2217
|
+
}
|
|
2053
2218
|
async discard(actor, id) {
|
|
2054
2219
|
return this.locked(id, async () => {
|
|
2055
2220
|
const draft = await this.load(id);
|
|
@@ -2102,7 +2267,7 @@ function decode(text, file) {
|
|
|
2102
2267
|
const commits = [draft.base.commit, draft.approval?.baseCommit, draft.handoff?.base, draft.handoff?.commit].filter((c) => c !== void 0);
|
|
2103
2268
|
if (!commits.every((c) => typeof c === "string" && COMMIT.test(c))) throw new Error(`${file} names a commit that is not a git object id`);
|
|
2104
2269
|
const kind = draft.kind ?? "rule";
|
|
2105
|
-
if (kind !== "rule" && kind !== "style" && kind !== "library") throw new Error(`${file} is a "${String(kind)}" draft, which this youi does not know`);
|
|
2270
|
+
if (kind !== "rule" && kind !== "style" && kind !== "library" && kind !== "ingest") throw new Error(`${file} is a "${String(kind)}" draft, which this youi does not know`);
|
|
2106
2271
|
return { ...draft, kind };
|
|
2107
2272
|
}
|
|
2108
2273
|
function checkId(id) {
|
|
@@ -2224,6 +2389,13 @@ export {
|
|
|
2224
2389
|
validateLibraryContent,
|
|
2225
2390
|
renderLibraryEntry,
|
|
2226
2391
|
describeLibrary,
|
|
2392
|
+
normalizeIngestContent,
|
|
2393
|
+
ingestDigest,
|
|
2394
|
+
keptEntries,
|
|
2395
|
+
validateIngestContent,
|
|
2396
|
+
describeIngest,
|
|
2397
|
+
ingestFiles,
|
|
2398
|
+
ingestSlug,
|
|
2227
2399
|
notRunReason,
|
|
2228
2400
|
comparePreview,
|
|
2229
2401
|
REQUESTS_DIR,
|
|
@@ -27450,7 +27450,7 @@ var FamilyId = external_exports.string().regex(FAMILY_ID_PATTERN, "expected <rol
|
|
|
27450
27450
|
function isFamilyId(id) {
|
|
27451
27451
|
return FAMILY_ID_PATTERN.test(id);
|
|
27452
27452
|
}
|
|
27453
|
-
var LIBRARY_SOURCE_KINDS = ["shadcn-registry", "npm", "github", "storybook"];
|
|
27453
|
+
var LIBRARY_SOURCE_KINDS = ["shadcn-registry", "npm", "github", "storybook", "figma", "design-md"];
|
|
27454
27454
|
var Iso = external_exports.string().datetime({ offset: true });
|
|
27455
27455
|
var LibraryLicense = external_exports.union([external_exports.literal("unknown"), external_exports.object({ spdx: external_exports.string().min(1), evidenceUrl: external_exports.string().url(), verifiedAt: Iso })]);
|
|
27456
27456
|
var LibraryEntry = external_exports.object({
|