uidex 0.3.0 → 0.4.0
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/cli/cli.cjs +122 -41
- package/dist/cli/cli.cjs.map +1 -1
- package/dist/cloud/index.cjs +22 -2
- package/dist/cloud/index.cjs.map +1 -1
- package/dist/cloud/index.js +22 -2
- package/dist/cloud/index.js.map +1 -1
- package/dist/headless/index.cjs +909 -346
- package/dist/headless/index.cjs.map +1 -1
- package/dist/headless/index.d.cts +6 -0
- package/dist/headless/index.d.ts +6 -0
- package/dist/headless/index.js +914 -346
- package/dist/headless/index.js.map +1 -1
- package/dist/index.cjs +2887 -1167
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -16
- package/dist/index.d.ts +83 -16
- package/dist/index.js +2919 -1175
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +2850 -1155
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +55 -8
- package/dist/react/index.d.ts +55 -8
- package/dist/react/index.js +2879 -1159
- package/dist/react/index.js.map +1 -1
- package/dist/scan/index.cjs +121 -42
- package/dist/scan/index.cjs.map +1 -1
- package/dist/scan/index.d.cts +5 -0
- package/dist/scan/index.d.ts +5 -0
- package/dist/scan/index.js +121 -42
- package/dist/scan/index.js.map +1 -1
- package/package.json +18 -17
- package/templates/claude/audit.md +8 -2
- package/templates/claude/rules.md +15 -0
- package/dist/cloud/index.d.cts +0 -108
- package/dist/cloud/index.d.ts +0 -108
package/dist/scan/index.cjs
CHANGED
|
@@ -60,6 +60,10 @@ var path = __toESM(require("path"), 1);
|
|
|
60
60
|
|
|
61
61
|
// src/scan/config.ts
|
|
62
62
|
var DEFAULT_TYPE_MODE = "strict";
|
|
63
|
+
var WELL_KNOWN_FILES = {
|
|
64
|
+
page: "uidex.page.ts",
|
|
65
|
+
feature: "uidex.feature.ts"
|
|
66
|
+
};
|
|
63
67
|
var ConfigError = class extends Error {
|
|
64
68
|
constructor(message) {
|
|
65
69
|
super(message);
|
|
@@ -97,14 +101,14 @@ var ALLOWED_AUDIT_KEYS = /* @__PURE__ */ new Set(["scopeLeak", "coverage", "acce
|
|
|
97
101
|
function fail(msg) {
|
|
98
102
|
throw new ConfigError(`Invalid .uidex.json: ${msg}`);
|
|
99
103
|
}
|
|
100
|
-
function assertObject(value,
|
|
104
|
+
function assertObject(value, path10) {
|
|
101
105
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
102
|
-
fail(`${
|
|
106
|
+
fail(`${path10} must be an object`);
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
|
-
function assertStringArray(value,
|
|
109
|
+
function assertStringArray(value, path10) {
|
|
106
110
|
if (!Array.isArray(value) || !value.every((v) => typeof v === "string")) {
|
|
107
|
-
fail(`${
|
|
111
|
+
fail(`${path10} must be a string[]`);
|
|
108
112
|
}
|
|
109
113
|
}
|
|
110
114
|
function validateConfig(raw) {
|
|
@@ -1825,7 +1829,24 @@ function resolve2(ctx) {
|
|
|
1825
1829
|
const routes = conventions.pages === "auto" ? detectRoutes(ctx.extracted.map((e) => e.file)) : [];
|
|
1826
1830
|
const handledPageFiles = /* @__PURE__ */ new Set();
|
|
1827
1831
|
for (const route of routes) {
|
|
1828
|
-
const
|
|
1832
|
+
const routeDir = path3.posix.dirname(route.file);
|
|
1833
|
+
const wellKnownPath = `${routeDir}/${WELL_KNOWN_FILES.page}`;
|
|
1834
|
+
const wellKnownExp = exportFor(wellKnownPath, "page");
|
|
1835
|
+
const routeExp = exportFor(route.file, "page");
|
|
1836
|
+
const exp = wellKnownExp ?? routeExp;
|
|
1837
|
+
const locFile = wellKnownExp ? wellKnownPath : route.file;
|
|
1838
|
+
if (wellKnownExp) handledPageFiles.add(wellKnownPath);
|
|
1839
|
+
handledPageFiles.add(route.file);
|
|
1840
|
+
if (wellKnownExp && routeExp) {
|
|
1841
|
+
diagnostics.push({
|
|
1842
|
+
code: "competing-uidex-export",
|
|
1843
|
+
severity: "warning",
|
|
1844
|
+
message: `Page metadata declared in both ${wellKnownPath} and ${route.file}; ${wellKnownPath} takes precedence.`,
|
|
1845
|
+
file: route.file,
|
|
1846
|
+
line: routeExp.loc.line,
|
|
1847
|
+
hint: `Remove the export from ${route.file} or delete ${wellKnownPath}.`
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1829
1850
|
if (exp && exp.id === false) continue;
|
|
1830
1851
|
const effectiveId = exp && typeof exp.id === "string" ? exp.id : route.id;
|
|
1831
1852
|
const meta = exp ? buildMetaFromExport(exp) : void 0;
|
|
@@ -1833,11 +1854,10 @@ function resolve2(ctx) {
|
|
|
1833
1854
|
const page = {
|
|
1834
1855
|
kind: "page",
|
|
1835
1856
|
id: effectiveId,
|
|
1836
|
-
loc: { file:
|
|
1857
|
+
loc: { file: locFile, line: exp?.loc.line },
|
|
1837
1858
|
...meta ? { meta } : {}
|
|
1838
1859
|
};
|
|
1839
1860
|
registry.add(page);
|
|
1840
|
-
handledPageFiles.add(route.file);
|
|
1841
1861
|
}
|
|
1842
1862
|
for (const ef of ctx.extracted) {
|
|
1843
1863
|
const exp = exportFor(ef.file.displayPath, "page");
|
|
@@ -1853,7 +1873,8 @@ function resolve2(ctx) {
|
|
|
1853
1873
|
}
|
|
1854
1874
|
const featureGlob = typeof conventions.features === "string" ? conventions.features : null;
|
|
1855
1875
|
const conventionalFeatureDirs = /* @__PURE__ */ new Set();
|
|
1856
|
-
const
|
|
1876
|
+
const featureExportFilesByDir = /* @__PURE__ */ new Map();
|
|
1877
|
+
const wellKnownFeatureFileByDir = /* @__PURE__ */ new Map();
|
|
1857
1878
|
const suppressedFeatureDirs = /* @__PURE__ */ new Set();
|
|
1858
1879
|
if (featureGlob) {
|
|
1859
1880
|
const re = globToRegExp(featureGlob + "/**");
|
|
@@ -1862,16 +1883,43 @@ function resolve2(ctx) {
|
|
|
1862
1883
|
const dir = extractFeatureDir(ef.file.displayPath, featureGlob);
|
|
1863
1884
|
if (!dir) continue;
|
|
1864
1885
|
conventionalFeatureDirs.add(dir);
|
|
1886
|
+
const isWellKnown = path3.posix.basename(ef.file.displayPath) === WELL_KNOWN_FILES.feature;
|
|
1887
|
+
if (isWellKnown) wellKnownFeatureFileByDir.set(dir, ef.file.displayPath);
|
|
1865
1888
|
const exp = exportFor(ef.file.displayPath, "feature");
|
|
1866
1889
|
if (exp) {
|
|
1867
1890
|
if (exp.id === false) suppressedFeatureDirs.add(dir);
|
|
1868
|
-
else
|
|
1869
|
-
|
|
1891
|
+
else {
|
|
1892
|
+
let arr = featureExportFilesByDir.get(dir);
|
|
1893
|
+
if (!arr) {
|
|
1894
|
+
arr = [];
|
|
1895
|
+
featureExportFilesByDir.set(dir, arr);
|
|
1896
|
+
}
|
|
1897
|
+
arr.push({ file: ef.file.displayPath, exp });
|
|
1898
|
+
}
|
|
1870
1899
|
}
|
|
1871
1900
|
}
|
|
1872
1901
|
for (const dir of conventionalFeatureDirs) {
|
|
1873
1902
|
if (suppressedFeatureDirs.has(dir)) continue;
|
|
1874
|
-
const
|
|
1903
|
+
const allExports = featureExportFilesByDir.get(dir) ?? [];
|
|
1904
|
+
const wellKnownPath = wellKnownFeatureFileByDir.get(dir);
|
|
1905
|
+
const wellKnownEntry = wellKnownPath ? allExports.find((e) => e.file === wellKnownPath) : void 0;
|
|
1906
|
+
let exp;
|
|
1907
|
+
if (wellKnownEntry) {
|
|
1908
|
+
exp = wellKnownEntry.exp;
|
|
1909
|
+
for (const other of allExports) {
|
|
1910
|
+
if (other.file === wellKnownEntry.file) continue;
|
|
1911
|
+
diagnostics.push({
|
|
1912
|
+
code: "competing-uidex-export",
|
|
1913
|
+
severity: "warning",
|
|
1914
|
+
message: `Feature metadata declared in both ${wellKnownEntry.file} and ${other.file}; ${wellKnownEntry.file} takes precedence.`,
|
|
1915
|
+
file: other.file,
|
|
1916
|
+
line: other.exp.loc.line,
|
|
1917
|
+
hint: `Remove the export from ${other.file} or delete ${wellKnownEntry.file}.`
|
|
1918
|
+
});
|
|
1919
|
+
}
|
|
1920
|
+
} else if (allExports.length > 0) {
|
|
1921
|
+
exp = allExports[0].exp;
|
|
1922
|
+
}
|
|
1875
1923
|
const id = exp && typeof exp.id === "string" ? exp.id : path3.posix.basename(dir);
|
|
1876
1924
|
const meta = exp ? buildMetaFromExport(exp) : void 0;
|
|
1877
1925
|
const feature = {
|
|
@@ -2004,11 +2052,12 @@ function resolve2(ctx) {
|
|
|
2004
2052
|
exp.id,
|
|
2005
2053
|
buildMetaFromExport(exp)
|
|
2006
2054
|
);
|
|
2055
|
+
const scope = computeScope(file);
|
|
2007
2056
|
const primitive = {
|
|
2008
2057
|
kind: "primitive",
|
|
2009
2058
|
id: exp.id,
|
|
2010
2059
|
loc: { file, line: exp.loc.line },
|
|
2011
|
-
scopes: [
|
|
2060
|
+
...scope ? { scopes: [scope] } : {},
|
|
2012
2061
|
...meta ? { meta } : {}
|
|
2013
2062
|
};
|
|
2014
2063
|
registry.add(primitive);
|
|
@@ -2020,11 +2069,12 @@ function resolve2(ctx) {
|
|
|
2020
2069
|
if (domPrimitives.length > 0) {
|
|
2021
2070
|
for (const p2 of domPrimitives) {
|
|
2022
2071
|
const meta = metaWithComposes("primitive", p2.id);
|
|
2072
|
+
const domScope = computeScope(p2.file);
|
|
2023
2073
|
const primitive = {
|
|
2024
2074
|
kind: "primitive",
|
|
2025
2075
|
id: p2.id,
|
|
2026
2076
|
loc: { file: p2.file, line: p2.line },
|
|
2027
|
-
scopes: [
|
|
2077
|
+
...domScope ? { scopes: [domScope] } : {},
|
|
2028
2078
|
...meta ? { meta } : {}
|
|
2029
2079
|
};
|
|
2030
2080
|
registry.add(primitive);
|
|
@@ -2034,13 +2084,13 @@ function resolve2(ctx) {
|
|
|
2034
2084
|
if (primitiveConventions && fileMatchesAny(file, primitiveConventions)) {
|
|
2035
2085
|
const name = kebab(baseName(file));
|
|
2036
2086
|
if (!name) continue;
|
|
2037
|
-
const
|
|
2087
|
+
const convScope = computeScope(file);
|
|
2038
2088
|
const meta = metaWithComposes("primitive", name);
|
|
2039
2089
|
const primitive = {
|
|
2040
2090
|
kind: "primitive",
|
|
2041
2091
|
id: name,
|
|
2042
2092
|
loc: { file },
|
|
2043
|
-
scopes: [
|
|
2093
|
+
...convScope ? { scopes: [convScope] } : {},
|
|
2044
2094
|
...meta ? { meta } : {}
|
|
2045
2095
|
};
|
|
2046
2096
|
registry.add(primitive);
|
|
@@ -2070,7 +2120,8 @@ function resolve2(ctx) {
|
|
|
2070
2120
|
kind: "flow",
|
|
2071
2121
|
id: flowExport.id,
|
|
2072
2122
|
loc: base.loc,
|
|
2073
|
-
touches: base.touches
|
|
2123
|
+
touches: base.touches,
|
|
2124
|
+
steps: base.steps
|
|
2074
2125
|
};
|
|
2075
2126
|
registry.add(flow);
|
|
2076
2127
|
} else {
|
|
@@ -2115,7 +2166,7 @@ function computeScope(displayPath) {
|
|
|
2115
2166
|
if (pagesIdx !== -1 && parts[pagesIdx + 1]) {
|
|
2116
2167
|
return `page:${parts[pagesIdx + 1]}`;
|
|
2117
2168
|
}
|
|
2118
|
-
return
|
|
2169
|
+
return null;
|
|
2119
2170
|
}
|
|
2120
2171
|
function extractFlowsFromSource(file) {
|
|
2121
2172
|
const flows = [];
|
|
@@ -2149,17 +2200,18 @@ function extractFlowsFromSource(file) {
|
|
|
2149
2200
|
kind: "flow",
|
|
2150
2201
|
id,
|
|
2151
2202
|
loc: { file: file.displayPath, line },
|
|
2152
|
-
touches: dedupe(touches.map((t) => t.id))
|
|
2203
|
+
touches: dedupe(touches.map((t) => t.id)),
|
|
2204
|
+
steps: touches.filter((t) => t.action).map((t) => ({ entityId: t.id, action: t.action }))
|
|
2153
2205
|
});
|
|
2154
2206
|
}
|
|
2155
2207
|
return flows;
|
|
2156
2208
|
}
|
|
2157
2209
|
function captureUidexIds(body) {
|
|
2158
2210
|
const out2 = [];
|
|
2159
|
-
const re = /uidex\(\s*(?:'([^']+)'|"([^"]+)"|`([^`$]+)`)\s*\)
|
|
2211
|
+
const re = /uidex\(\s*(?:'([^']+)'|"([^"]+)"|`([^`$]+)`)\s*\)(?:\.(\w+)\s*\()?/g;
|
|
2160
2212
|
let m;
|
|
2161
2213
|
while ((m = re.exec(body)) !== null) {
|
|
2162
|
-
out2.push({ id: m[1] || m[2] || m[3] });
|
|
2214
|
+
out2.push({ id: m[1] || m[2] || m[3], action: m[4] });
|
|
2163
2215
|
}
|
|
2164
2216
|
return out2;
|
|
2165
2217
|
}
|
|
@@ -2168,6 +2220,7 @@ function dedupe(arr) {
|
|
|
2168
2220
|
}
|
|
2169
2221
|
|
|
2170
2222
|
// src/scan/audit.ts
|
|
2223
|
+
var path4 = __toESM(require("path"), 1);
|
|
2171
2224
|
var MARKER_FILENAMES = ["UIDEX_PAGE.md", "UIDEX_FEATURE.md"];
|
|
2172
2225
|
function audit(opts) {
|
|
2173
2226
|
const diagnostics = [];
|
|
@@ -2269,6 +2322,32 @@ function audit(opts) {
|
|
|
2269
2322
|
}
|
|
2270
2323
|
}
|
|
2271
2324
|
}
|
|
2325
|
+
if (lint) {
|
|
2326
|
+
const scannedPaths = new Set(files.map((f) => f.displayPath));
|
|
2327
|
+
for (const ef of extracted) {
|
|
2328
|
+
if (!ef.metadata) continue;
|
|
2329
|
+
for (const m of ef.metadata) {
|
|
2330
|
+
if (m.kind !== "page" && m.kind !== "feature") continue;
|
|
2331
|
+
if (typeof m.id !== "string") continue;
|
|
2332
|
+
const filePath = ef.file.displayPath;
|
|
2333
|
+
const wellKnownName = WELL_KNOWN_FILES[m.kind];
|
|
2334
|
+
if (path4.posix.basename(filePath) === wellKnownName) continue;
|
|
2335
|
+
const dir = path4.posix.dirname(filePath);
|
|
2336
|
+
const wellKnownPath = dir === "." ? wellKnownName : `${dir}/${wellKnownName}`;
|
|
2337
|
+
if (scannedPaths.has(wellKnownPath)) continue;
|
|
2338
|
+
const kindLabel = m.kind === "page" ? "Page" : "Feature";
|
|
2339
|
+
diagnostics.push({
|
|
2340
|
+
code: "prefer-well-known-file",
|
|
2341
|
+
severity: "info",
|
|
2342
|
+
message: `${kindLabel} "${m.id}" metadata lives on ${filePath}; prefer ${wellKnownPath}`,
|
|
2343
|
+
file: filePath,
|
|
2344
|
+
line: m.loc.line,
|
|
2345
|
+
entity: { kind: m.kind, id: m.id },
|
|
2346
|
+
hint: `Move the \`export const uidex\` block to ${wellKnownPath} and remove it from ${filePath}.`
|
|
2347
|
+
});
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2272
2351
|
if (lint) {
|
|
2273
2352
|
for (const f of files) {
|
|
2274
2353
|
const lines = f.content.split("\n");
|
|
@@ -2305,8 +2384,8 @@ function audit(opts) {
|
|
|
2305
2384
|
baseName2.replace(/\.(tsx|ts|jsx|js|mjs|cjs)$/, "").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase()
|
|
2306
2385
|
);
|
|
2307
2386
|
if (!primitive) continue;
|
|
2308
|
-
const scope = primitive.scopes?.[0]
|
|
2309
|
-
if (scope
|
|
2387
|
+
const scope = primitive.scopes?.[0];
|
|
2388
|
+
if (!scope) continue;
|
|
2310
2389
|
const [kind, id] = scope.split(":");
|
|
2311
2390
|
const importerSegments = f.displayPath.split("/");
|
|
2312
2391
|
if (!importerSegments.includes(id) || !importerSegments.includes(kind + "s")) {
|
|
@@ -2704,7 +2783,7 @@ function parseGitHubRef(ref) {
|
|
|
2704
2783
|
|
|
2705
2784
|
// src/scan/scaffold.ts
|
|
2706
2785
|
var fs3 = __toESM(require("fs"), 1);
|
|
2707
|
-
var
|
|
2786
|
+
var path5 = __toESM(require("path"), 1);
|
|
2708
2787
|
function scaffoldWidgetSpec(opts) {
|
|
2709
2788
|
const {
|
|
2710
2789
|
registry,
|
|
@@ -2719,7 +2798,7 @@ function scaffoldWidgetSpec(opts) {
|
|
|
2719
2798
|
}
|
|
2720
2799
|
const criteria = widget.meta?.acceptance ?? [];
|
|
2721
2800
|
const filename = `widget-${widgetId}.spec.ts`;
|
|
2722
|
-
const outputPath =
|
|
2801
|
+
const outputPath = path5.resolve(outDir, filename);
|
|
2723
2802
|
if (fs3.existsSync(outputPath) && !force) {
|
|
2724
2803
|
return {
|
|
2725
2804
|
outputPath,
|
|
@@ -2733,7 +2812,7 @@ function scaffoldWidgetSpec(opts) {
|
|
|
2733
2812
|
criteria,
|
|
2734
2813
|
fixtureImport
|
|
2735
2814
|
});
|
|
2736
|
-
fs3.mkdirSync(
|
|
2815
|
+
fs3.mkdirSync(path5.dirname(outputPath), { recursive: true });
|
|
2737
2816
|
fs3.writeFileSync(outputPath, content, "utf8");
|
|
2738
2817
|
return { outputPath, written: true, skipped: false };
|
|
2739
2818
|
}
|
|
@@ -2767,7 +2846,7 @@ function renderSpec(args) {
|
|
|
2767
2846
|
|
|
2768
2847
|
// src/scan/pipeline.ts
|
|
2769
2848
|
var fs4 = __toESM(require("fs"), 1);
|
|
2770
|
-
var
|
|
2849
|
+
var path6 = __toESM(require("path"), 1);
|
|
2771
2850
|
function runScan(opts = {}) {
|
|
2772
2851
|
const cwd = opts.cwd ?? process.cwd();
|
|
2773
2852
|
const configs = opts.configs ?? discover({ cwd });
|
|
@@ -2799,7 +2878,7 @@ function runOne(dc, opts) {
|
|
|
2799
2878
|
gitContext,
|
|
2800
2879
|
typeMode: config.typeMode
|
|
2801
2880
|
});
|
|
2802
|
-
const outputPath =
|
|
2881
|
+
const outputPath = path6.resolve(configDir, config.output);
|
|
2803
2882
|
const outputRel = config.output;
|
|
2804
2883
|
let existingOnDisk = null;
|
|
2805
2884
|
if (opts.check) {
|
|
@@ -2835,29 +2914,29 @@ function runOne(dc, opts) {
|
|
|
2835
2914
|
};
|
|
2836
2915
|
}
|
|
2837
2916
|
function writeScanResult(result) {
|
|
2838
|
-
fs4.mkdirSync(
|
|
2917
|
+
fs4.mkdirSync(path6.dirname(result.outputPath), { recursive: true });
|
|
2839
2918
|
fs4.writeFileSync(result.outputPath, result.generated, "utf8");
|
|
2840
2919
|
}
|
|
2841
2920
|
|
|
2842
2921
|
// src/scan/cli.ts
|
|
2843
2922
|
var fs7 = __toESM(require("fs"), 1);
|
|
2844
|
-
var
|
|
2923
|
+
var path9 = __toESM(require("path"), 1);
|
|
2845
2924
|
|
|
2846
2925
|
// src/scan/ai/index.ts
|
|
2847
2926
|
var p = __toESM(require("@clack/prompts"), 1);
|
|
2848
2927
|
|
|
2849
2928
|
// src/scan/ai/providers/claude.ts
|
|
2850
2929
|
var fs6 = __toESM(require("fs"), 1);
|
|
2851
|
-
var
|
|
2930
|
+
var path8 = __toESM(require("path"), 1);
|
|
2852
2931
|
|
|
2853
2932
|
// src/scan/ai/templates.ts
|
|
2854
2933
|
var fs5 = __toESM(require("fs"), 1);
|
|
2855
|
-
var
|
|
2934
|
+
var path7 = __toESM(require("path"), 1);
|
|
2856
2935
|
function templatePath(rel) {
|
|
2857
2936
|
const candidates = [
|
|
2858
|
-
|
|
2937
|
+
path7.resolve(__dirname, "../../templates", rel),
|
|
2859
2938
|
// dist/cli/cli.cjs → ../../templates
|
|
2860
|
-
|
|
2939
|
+
path7.resolve(__dirname, "../../../templates", rel)
|
|
2861
2940
|
// src/scan/ai/foo.ts → ../../../templates
|
|
2862
2941
|
];
|
|
2863
2942
|
for (const c of candidates) {
|
|
@@ -2889,7 +2968,7 @@ var claudeProvider = {
|
|
|
2889
2968
|
async install({ cwd, force }) {
|
|
2890
2969
|
const changes = [];
|
|
2891
2970
|
for (const file of CLAUDE_FILES) {
|
|
2892
|
-
const dest =
|
|
2971
|
+
const dest = path8.join(cwd, file.dest);
|
|
2893
2972
|
const exists = fs6.existsSync(dest);
|
|
2894
2973
|
if (exists && !force) {
|
|
2895
2974
|
changes.push({
|
|
@@ -2899,7 +2978,7 @@ var claudeProvider = {
|
|
|
2899
2978
|
});
|
|
2900
2979
|
continue;
|
|
2901
2980
|
}
|
|
2902
|
-
fs6.mkdirSync(
|
|
2981
|
+
fs6.mkdirSync(path8.dirname(dest), { recursive: true });
|
|
2903
2982
|
fs6.writeFileSync(dest, readTemplate(file.template));
|
|
2904
2983
|
changes.push({
|
|
2905
2984
|
path: file.dest,
|
|
@@ -2911,7 +2990,7 @@ var claudeProvider = {
|
|
|
2911
2990
|
async uninstall({ cwd }) {
|
|
2912
2991
|
const changes = [];
|
|
2913
2992
|
for (const file of CLAUDE_FILES) {
|
|
2914
|
-
const dest =
|
|
2993
|
+
const dest = path8.join(cwd, file.dest);
|
|
2915
2994
|
if (!fs6.existsSync(dest)) {
|
|
2916
2995
|
changes.push({ path: file.dest, action: "skipped", reason: "absent" });
|
|
2917
2996
|
continue;
|
|
@@ -2919,9 +2998,9 @@ var claudeProvider = {
|
|
|
2919
2998
|
fs6.unlinkSync(dest);
|
|
2920
2999
|
changes.push({ path: file.dest, action: "removed" });
|
|
2921
3000
|
}
|
|
2922
|
-
cleanupEmpty(
|
|
2923
|
-
cleanupEmpty(
|
|
2924
|
-
cleanupEmpty(
|
|
3001
|
+
cleanupEmpty(path8.join(cwd, ".claude/commands/uidex"));
|
|
3002
|
+
cleanupEmpty(path8.join(cwd, ".claude/commands"));
|
|
3003
|
+
cleanupEmpty(path8.join(cwd, ".claude/rules"));
|
|
2925
3004
|
return { changes };
|
|
2926
3005
|
}
|
|
2927
3006
|
};
|
|
@@ -3132,7 +3211,7 @@ function helpText2() {
|
|
|
3132
3211
|
].join("\n");
|
|
3133
3212
|
}
|
|
3134
3213
|
function runInit(cwd, w) {
|
|
3135
|
-
const configPath =
|
|
3214
|
+
const configPath = path9.join(cwd, CONFIG_FILENAME);
|
|
3136
3215
|
if (fs7.existsSync(configPath)) {
|
|
3137
3216
|
w.err(`.uidex.json already exists at ${configPath}`);
|
|
3138
3217
|
return w.result(1);
|
|
@@ -3144,7 +3223,7 @@ function runInit(cwd, w) {
|
|
|
3144
3223
|
};
|
|
3145
3224
|
fs7.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
3146
3225
|
w.out(`Created ${configPath}`);
|
|
3147
|
-
const gitignorePath =
|
|
3226
|
+
const gitignorePath = path9.join(cwd, ".gitignore");
|
|
3148
3227
|
const entry = "*.gen.ts";
|
|
3149
3228
|
if (fs7.existsSync(gitignorePath)) {
|
|
3150
3229
|
const existing = fs7.readFileSync(gitignorePath, "utf8");
|
|
@@ -3222,7 +3301,7 @@ function runScaffold(cwd, args, flags, w) {
|
|
|
3222
3301
|
for (const r of results) {
|
|
3223
3302
|
const widget = r.registry.get("widget", id);
|
|
3224
3303
|
if (!widget) continue;
|
|
3225
|
-
const outDir =
|
|
3304
|
+
const outDir = path9.resolve(r.configDir, "e2e");
|
|
3226
3305
|
const result = scaffoldWidgetSpec({
|
|
3227
3306
|
registry: r.registry,
|
|
3228
3307
|
widgetId: id,
|