uidex 0.4.0 → 0.5.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 +996 -73
- package/dist/cli/cli.cjs.map +1 -1
- package/dist/cloud/index.cjs +375 -72
- package/dist/cloud/index.cjs.map +1 -1
- package/dist/cloud/index.d.cts +82 -0
- package/dist/cloud/index.d.ts +82 -0
- package/dist/cloud/index.js +376 -71
- package/dist/cloud/index.js.map +1 -1
- package/dist/headless/index.cjs +620 -469
- package/dist/headless/index.cjs.map +1 -1
- package/dist/headless/index.d.cts +77 -75
- package/dist/headless/index.d.ts +77 -75
- package/dist/headless/index.js +624 -469
- package/dist/headless/index.js.map +1 -1
- package/dist/index.cjs +4255 -2884
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +275 -234
- package/dist/index.d.ts +275 -234
- package/dist/index.js +4277 -2890
- package/dist/index.js.map +1 -1
- package/dist/playwright/index.cjs +4 -4
- package/dist/playwright/index.cjs.map +1 -1
- package/dist/playwright/index.js +3 -3
- package/dist/playwright/index.js.map +1 -1
- package/dist/playwright/reporter.cjs +3 -3
- package/dist/playwright/reporter.cjs.map +1 -1
- package/dist/playwright/reporter.js +3 -3
- package/dist/playwright/reporter.js.map +1 -1
- package/dist/react/index.cjs +4298 -2908
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +206 -200
- package/dist/react/index.d.ts +206 -200
- package/dist/react/index.js +4334 -2924
- package/dist/react/index.js.map +1 -1
- package/dist/scan/index.cjs +91 -40
- package/dist/scan/index.cjs.map +1 -1
- package/dist/scan/index.d.cts +26 -0
- package/dist/scan/index.d.ts +26 -0
- package/dist/scan/index.js +90 -39
- package/dist/scan/index.js.map +1 -1
- package/package.json +23 -22
- package/templates/claude/api.md +110 -0
package/dist/scan/index.d.cts
CHANGED
|
@@ -65,6 +65,26 @@ type EntityByKind<K extends EntityKind> = Extract<Entity, {
|
|
|
65
65
|
kind: K;
|
|
66
66
|
}>;
|
|
67
67
|
|
|
68
|
+
interface ReportRecord {
|
|
69
|
+
id: string;
|
|
70
|
+
entity?: string;
|
|
71
|
+
reporter?: {
|
|
72
|
+
id?: string;
|
|
73
|
+
email?: string;
|
|
74
|
+
name?: string;
|
|
75
|
+
};
|
|
76
|
+
title?: string;
|
|
77
|
+
body: string;
|
|
78
|
+
type: string;
|
|
79
|
+
severity: string;
|
|
80
|
+
status: string;
|
|
81
|
+
labels?: string[];
|
|
82
|
+
url: string;
|
|
83
|
+
route?: string;
|
|
84
|
+
pageTitle?: string;
|
|
85
|
+
screenshot?: string;
|
|
86
|
+
createdAt: string;
|
|
87
|
+
}
|
|
68
88
|
interface Registry {
|
|
69
89
|
add(entity: Entity): void;
|
|
70
90
|
get<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
|
|
@@ -72,6 +92,11 @@ interface Registry {
|
|
|
72
92
|
query(predicate: (entity: Entity) => boolean): Entity[];
|
|
73
93
|
byScope(scope: Scope): Entity[];
|
|
74
94
|
touchedBy(flowId: string): Entity[];
|
|
95
|
+
setReports(kind: EntityKind, id: string, reports: readonly ReportRecord[]): void;
|
|
96
|
+
getReports(kind: EntityKind, id: string): readonly ReportRecord[];
|
|
97
|
+
listReportKeys(): readonly string[];
|
|
98
|
+
archiveReport?: (reportId: string, reason?: string) => void | Promise<void>;
|
|
99
|
+
onReportsChange(cb: () => void): () => void;
|
|
75
100
|
}
|
|
76
101
|
|
|
77
102
|
interface SourceConfig {
|
|
@@ -351,6 +376,7 @@ declare namespace Uidex {
|
|
|
351
376
|
interface Feature<FeatureIds extends string = string> {
|
|
352
377
|
feature: FeatureIds | false;
|
|
353
378
|
name?: string;
|
|
379
|
+
features?: readonly FeatureIds[];
|
|
354
380
|
acceptance?: readonly string[];
|
|
355
381
|
description?: string;
|
|
356
382
|
}
|
package/dist/scan/index.d.ts
CHANGED
|
@@ -65,6 +65,26 @@ type EntityByKind<K extends EntityKind> = Extract<Entity, {
|
|
|
65
65
|
kind: K;
|
|
66
66
|
}>;
|
|
67
67
|
|
|
68
|
+
interface ReportRecord {
|
|
69
|
+
id: string;
|
|
70
|
+
entity?: string;
|
|
71
|
+
reporter?: {
|
|
72
|
+
id?: string;
|
|
73
|
+
email?: string;
|
|
74
|
+
name?: string;
|
|
75
|
+
};
|
|
76
|
+
title?: string;
|
|
77
|
+
body: string;
|
|
78
|
+
type: string;
|
|
79
|
+
severity: string;
|
|
80
|
+
status: string;
|
|
81
|
+
labels?: string[];
|
|
82
|
+
url: string;
|
|
83
|
+
route?: string;
|
|
84
|
+
pageTitle?: string;
|
|
85
|
+
screenshot?: string;
|
|
86
|
+
createdAt: string;
|
|
87
|
+
}
|
|
68
88
|
interface Registry {
|
|
69
89
|
add(entity: Entity): void;
|
|
70
90
|
get<K extends EntityKind>(kind: K, id: string): EntityByKind<K> | undefined;
|
|
@@ -72,6 +92,11 @@ interface Registry {
|
|
|
72
92
|
query(predicate: (entity: Entity) => boolean): Entity[];
|
|
73
93
|
byScope(scope: Scope): Entity[];
|
|
74
94
|
touchedBy(flowId: string): Entity[];
|
|
95
|
+
setReports(kind: EntityKind, id: string, reports: readonly ReportRecord[]): void;
|
|
96
|
+
getReports(kind: EntityKind, id: string): readonly ReportRecord[];
|
|
97
|
+
listReportKeys(): readonly string[];
|
|
98
|
+
archiveReport?: (reportId: string, reason?: string) => void | Promise<void>;
|
|
99
|
+
onReportsChange(cb: () => void): () => void;
|
|
75
100
|
}
|
|
76
101
|
|
|
77
102
|
interface SourceConfig {
|
|
@@ -351,6 +376,7 @@ declare namespace Uidex {
|
|
|
351
376
|
interface Feature<FeatureIds extends string = string> {
|
|
352
377
|
feature: FeatureIds | false;
|
|
353
378
|
name?: string;
|
|
379
|
+
features?: readonly FeatureIds[];
|
|
354
380
|
acceptance?: readonly string[];
|
|
355
381
|
description?: string;
|
|
356
382
|
}
|
package/dist/scan/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// src/scan/discover.ts
|
|
1
|
+
// src/scanner/scan/discover.ts
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
|
|
5
|
-
// src/scan/config.ts
|
|
5
|
+
// src/scanner/scan/config.ts
|
|
6
6
|
var DEFAULT_TYPE_MODE = "strict";
|
|
7
7
|
var WELL_KNOWN_FILES = {
|
|
8
8
|
page: "uidex.page.ts",
|
|
@@ -166,7 +166,7 @@ var DEFAULT_CONVENTIONS = {
|
|
|
166
166
|
regions: "landmarks"
|
|
167
167
|
};
|
|
168
168
|
|
|
169
|
-
// src/scan/discover.ts
|
|
169
|
+
// src/scanner/scan/discover.ts
|
|
170
170
|
var CONFIG_FILENAME = ".uidex.json";
|
|
171
171
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
172
172
|
"node_modules",
|
|
@@ -225,7 +225,7 @@ function discover(options = {}) {
|
|
|
225
225
|
return results.sort((a, b) => a.configPath.localeCompare(b.configPath));
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
// src/scan/walk.ts
|
|
228
|
+
// src/scanner/scan/walk.ts
|
|
229
229
|
import * as fs2 from "fs";
|
|
230
230
|
import * as path2 from "path";
|
|
231
231
|
var DEFAULT_INCLUDES = ["**/*.{ts,tsx,js,jsx,mjs,cjs}"];
|
|
@@ -350,7 +350,7 @@ function* walkDir(root, dir) {
|
|
|
350
350
|
}
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
-
// src/scan/extract-uidex-export.ts
|
|
353
|
+
// src/scanner/scan/extract-uidex-export.ts
|
|
354
354
|
var KIND_DISCRIMINATORS = [
|
|
355
355
|
"page",
|
|
356
356
|
"feature",
|
|
@@ -368,7 +368,13 @@ var ALLOWED_FIELDS = {
|
|
|
368
368
|
"acceptance",
|
|
369
369
|
"description"
|
|
370
370
|
]),
|
|
371
|
-
feature: /* @__PURE__ */ new Set([
|
|
371
|
+
feature: /* @__PURE__ */ new Set([
|
|
372
|
+
"feature",
|
|
373
|
+
"name",
|
|
374
|
+
"features",
|
|
375
|
+
"acceptance",
|
|
376
|
+
"description"
|
|
377
|
+
]),
|
|
372
378
|
primitive: /* @__PURE__ */ new Set(["primitive", "name", "description"]),
|
|
373
379
|
widget: /* @__PURE__ */ new Set(["widget", "name", "acceptance", "description"]),
|
|
374
380
|
flow: /* @__PURE__ */ new Set(["flow", "notFlow", "name", "description"])
|
|
@@ -1104,7 +1110,7 @@ function buildMetadata(value, file, headerPos, diagnostics) {
|
|
|
1104
1110
|
line: pos.line
|
|
1105
1111
|
});
|
|
1106
1112
|
}
|
|
1107
|
-
const features = kind === "page" ? readStringArrayField(byKey, "features") : void 0;
|
|
1113
|
+
const features = kind === "page" || kind === "feature" ? readStringArrayField(byKey, "features") : void 0;
|
|
1108
1114
|
const widgets = kind === "page" ? readStringArrayField(byKey, "widgets") : void 0;
|
|
1109
1115
|
const notFlow = kind === "flow" && discriminator === "notFlow" ? true : void 0;
|
|
1110
1116
|
const metadata = {
|
|
@@ -1199,7 +1205,7 @@ function posAt(content, offset) {
|
|
|
1199
1205
|
return { offset, line, column: offset - lineStart + 1 };
|
|
1200
1206
|
}
|
|
1201
1207
|
|
|
1202
|
-
// src/scan/jsx-ancestry.ts
|
|
1208
|
+
// src/scanner/scan/jsx-ancestry.ts
|
|
1203
1209
|
var DATA_ATTR_RE = /\bdata-uidex(?:-(region|widget|primitive))?\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
1204
1210
|
function parseDataAttrs(tagSource) {
|
|
1205
1211
|
if (!tagSource.includes("data-uidex")) return [];
|
|
@@ -1388,7 +1394,7 @@ function findTagEnd(content, start) {
|
|
|
1388
1394
|
return -1;
|
|
1389
1395
|
}
|
|
1390
1396
|
|
|
1391
|
-
// src/scan/extract.ts
|
|
1397
|
+
// src/scanner/scan/extract.ts
|
|
1392
1398
|
var JSDOC_BLOCK = /\/\*\*([\s\S]*?)\*\//g;
|
|
1393
1399
|
function lineAt(content, index) {
|
|
1394
1400
|
let line = 1;
|
|
@@ -1491,10 +1497,10 @@ function extractOne(file) {
|
|
|
1491
1497
|
return annotations;
|
|
1492
1498
|
}
|
|
1493
1499
|
|
|
1494
|
-
// src/scan/resolve.ts
|
|
1500
|
+
// src/scanner/scan/resolve.ts
|
|
1495
1501
|
import * as path3 from "path";
|
|
1496
1502
|
|
|
1497
|
-
// src/entities/types.ts
|
|
1503
|
+
// src/shared/entities/types.ts
|
|
1498
1504
|
var ENTITY_KINDS = [
|
|
1499
1505
|
"route",
|
|
1500
1506
|
"page",
|
|
@@ -1527,7 +1533,7 @@ function assertEntityKind(kind) {
|
|
|
1527
1533
|
if (!KIND_SET.has(kind)) throw new UnknownEntityKindError(kind);
|
|
1528
1534
|
}
|
|
1529
1535
|
|
|
1530
|
-
// src/entities/registry.ts
|
|
1536
|
+
// src/shared/entities/registry.ts
|
|
1531
1537
|
function emptyStore() {
|
|
1532
1538
|
return {
|
|
1533
1539
|
route: /* @__PURE__ */ new Map(),
|
|
@@ -1609,10 +1615,33 @@ function createRegistry() {
|
|
|
1609
1615
|
return ids.has(entity.id);
|
|
1610
1616
|
});
|
|
1611
1617
|
};
|
|
1612
|
-
|
|
1618
|
+
const reports = /* @__PURE__ */ new Map();
|
|
1619
|
+
const reportsCbs = /* @__PURE__ */ new Set();
|
|
1620
|
+
const setReports = (kind, id, records) => {
|
|
1621
|
+
reports.set(`${kind}:${id}`, records);
|
|
1622
|
+
for (const cb of reportsCbs) cb();
|
|
1623
|
+
};
|
|
1624
|
+
const getReports = (kind, id) => reports.get(`${kind}:${id}`) ?? [];
|
|
1625
|
+
const listReportKeys = () => Array.from(reports.keys());
|
|
1626
|
+
const onReportsChange = (cb) => {
|
|
1627
|
+
reportsCbs.add(cb);
|
|
1628
|
+
return () => reportsCbs.delete(cb);
|
|
1629
|
+
};
|
|
1630
|
+
return {
|
|
1631
|
+
add,
|
|
1632
|
+
get,
|
|
1633
|
+
list,
|
|
1634
|
+
query,
|
|
1635
|
+
byScope,
|
|
1636
|
+
touchedBy,
|
|
1637
|
+
setReports,
|
|
1638
|
+
getReports,
|
|
1639
|
+
listReportKeys,
|
|
1640
|
+
onReportsChange
|
|
1641
|
+
};
|
|
1613
1642
|
}
|
|
1614
1643
|
|
|
1615
|
-
// src/scan/routes.ts
|
|
1644
|
+
// src/scanner/scan/routes.ts
|
|
1616
1645
|
var PAGE_BASENAME = /^page\.(tsx|ts|jsx|js|mjs|cjs)$/;
|
|
1617
1646
|
var PAGES_ROUTER_BASENAME = /\.(tsx|ts|jsx|js|mjs|cjs)$/;
|
|
1618
1647
|
var ROUTE_BASENAME = /^route\.(tsx|ts|jsx|js|mjs|cjs)$/;
|
|
@@ -1678,7 +1707,7 @@ function pathToId(routePath) {
|
|
|
1678
1707
|
return routePath.replace(/^\/+/, "").replace(/\[\.{3}([^\]]+)\]/g, "$1").replace(/\[([^\]]+)\]/g, "$1").replace(/\//g, "-").replace(/[^a-zA-Z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
1679
1708
|
}
|
|
1680
1709
|
|
|
1681
|
-
// src/scan/resolve.ts
|
|
1710
|
+
// src/scanner/scan/resolve.ts
|
|
1682
1711
|
var DOM_ATTR_KINDS = /* @__PURE__ */ new Set([
|
|
1683
1712
|
"element",
|
|
1684
1713
|
"region",
|
|
@@ -2163,7 +2192,7 @@ function dedupe(arr) {
|
|
|
2163
2192
|
return Array.from(new Set(arr));
|
|
2164
2193
|
}
|
|
2165
2194
|
|
|
2166
|
-
// src/scan/audit.ts
|
|
2195
|
+
// src/scanner/scan/audit.ts
|
|
2167
2196
|
import * as path4 from "path";
|
|
2168
2197
|
var MARKER_FILENAMES = ["UIDEX_PAGE.md", "UIDEX_FEATURE.md"];
|
|
2169
2198
|
function audit(opts) {
|
|
@@ -2318,6 +2347,15 @@ function audit(opts) {
|
|
|
2318
2347
|
const primitives = registry.list("primitive");
|
|
2319
2348
|
const byName = /* @__PURE__ */ new Map();
|
|
2320
2349
|
for (const p2 of primitives) byName.set(p2.id, p2);
|
|
2350
|
+
const declaredFeatures = /* @__PURE__ */ new Map();
|
|
2351
|
+
for (const ef of extracted) {
|
|
2352
|
+
if (!ef.metadata) continue;
|
|
2353
|
+
for (const m of ef.metadata) {
|
|
2354
|
+
if (m.features && m.features.length > 0) {
|
|
2355
|
+
declaredFeatures.set(ef.file.displayPath, new Set(m.features));
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2321
2359
|
for (const f of files) {
|
|
2322
2360
|
const importRe = /import\s+(?:[^'"]+)\s+from\s+['"]([^'"]+)['"]/g;
|
|
2323
2361
|
let m;
|
|
@@ -2332,14 +2370,19 @@ function audit(opts) {
|
|
|
2332
2370
|
if (!scope) continue;
|
|
2333
2371
|
const [kind, id] = scope.split(":");
|
|
2334
2372
|
const importerSegments = f.displayPath.split("/");
|
|
2335
|
-
if (
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
});
|
|
2373
|
+
if (importerSegments.includes(id) && importerSegments.includes(kind + "s")) {
|
|
2374
|
+
continue;
|
|
2375
|
+
}
|
|
2376
|
+
if (kind === "feature" && importerSegments.includes(id)) continue;
|
|
2377
|
+
if (kind === "feature" && declaredFeatures.get(f.displayPath)?.has(id)) {
|
|
2378
|
+
continue;
|
|
2342
2379
|
}
|
|
2380
|
+
diagnostics.push({
|
|
2381
|
+
code: "scope-leak",
|
|
2382
|
+
severity: "warning",
|
|
2383
|
+
message: `Primitive "${primitive.id}" is scoped to ${scope} but is imported from ${f.displayPath}`,
|
|
2384
|
+
file: f.displayPath
|
|
2385
|
+
});
|
|
2343
2386
|
}
|
|
2344
2387
|
}
|
|
2345
2388
|
}
|
|
@@ -2513,7 +2556,7 @@ function stableReplacer(_key, value) {
|
|
|
2513
2556
|
return value;
|
|
2514
2557
|
}
|
|
2515
2558
|
|
|
2516
|
-
// src/scan/emit.ts
|
|
2559
|
+
// src/scanner/scan/emit.ts
|
|
2517
2560
|
function sortById(arr) {
|
|
2518
2561
|
return [...arr].sort((a, b) => a.id.localeCompare(b.id));
|
|
2519
2562
|
}
|
|
@@ -2637,6 +2680,7 @@ function emit(opts) {
|
|
|
2637
2680
|
lines.push(" export interface Feature {");
|
|
2638
2681
|
lines.push(" feature: FeatureId | false");
|
|
2639
2682
|
lines.push(" name?: string");
|
|
2683
|
+
lines.push(" features?: readonly FeatureId[]");
|
|
2640
2684
|
lines.push(" acceptance?: readonly string[]");
|
|
2641
2685
|
lines.push(" description?: string");
|
|
2642
2686
|
lines.push(" }");
|
|
@@ -2693,7 +2737,7 @@ function emit(opts) {
|
|
|
2693
2737
|
return lines.join("\n");
|
|
2694
2738
|
}
|
|
2695
2739
|
|
|
2696
|
-
// src/scan/git.ts
|
|
2740
|
+
// src/scanner/scan/git.ts
|
|
2697
2741
|
import { execSync } from "child_process";
|
|
2698
2742
|
function runGit(args, cwd) {
|
|
2699
2743
|
try {
|
|
@@ -2725,7 +2769,7 @@ function parseGitHubRef(ref) {
|
|
|
2725
2769
|
return m ? m[1] : null;
|
|
2726
2770
|
}
|
|
2727
2771
|
|
|
2728
|
-
// src/scan/scaffold.ts
|
|
2772
|
+
// src/scanner/scan/scaffold.ts
|
|
2729
2773
|
import * as fs3 from "fs";
|
|
2730
2774
|
import * as path5 from "path";
|
|
2731
2775
|
function scaffoldWidgetSpec(opts) {
|
|
@@ -2788,7 +2832,7 @@ function renderSpec(args) {
|
|
|
2788
2832
|
return lines.join("\n");
|
|
2789
2833
|
}
|
|
2790
2834
|
|
|
2791
|
-
// src/scan/pipeline.ts
|
|
2835
|
+
// src/scanner/scan/pipeline.ts
|
|
2792
2836
|
import * as fs4 from "fs";
|
|
2793
2837
|
import * as path6 from "path";
|
|
2794
2838
|
function runScan(opts = {}) {
|
|
@@ -2862,18 +2906,18 @@ function writeScanResult(result) {
|
|
|
2862
2906
|
fs4.writeFileSync(result.outputPath, result.generated, "utf8");
|
|
2863
2907
|
}
|
|
2864
2908
|
|
|
2865
|
-
// src/scan/cli.ts
|
|
2909
|
+
// src/scanner/scan/cli.ts
|
|
2866
2910
|
import * as fs7 from "fs";
|
|
2867
2911
|
import * as path9 from "path";
|
|
2868
2912
|
|
|
2869
|
-
// src/scan/ai/index.ts
|
|
2913
|
+
// src/scanner/scan/ai/index.ts
|
|
2870
2914
|
import * as p from "@clack/prompts";
|
|
2871
2915
|
|
|
2872
|
-
// src/scan/ai/providers/claude.ts
|
|
2916
|
+
// src/scanner/scan/ai/providers/claude.ts
|
|
2873
2917
|
import * as fs6 from "fs";
|
|
2874
2918
|
import * as path8 from "path";
|
|
2875
2919
|
|
|
2876
|
-
// src/scan/ai/templates.ts
|
|
2920
|
+
// src/scanner/scan/ai/templates.ts
|
|
2877
2921
|
import * as fs5 from "fs";
|
|
2878
2922
|
import * as path7 from "path";
|
|
2879
2923
|
function templatePath(rel) {
|
|
@@ -2900,15 +2944,16 @@ function readTemplate(rel) {
|
|
|
2900
2944
|
return fs5.readFileSync(templatePath(rel), "utf8");
|
|
2901
2945
|
}
|
|
2902
2946
|
|
|
2903
|
-
// src/scan/ai/providers/claude.ts
|
|
2947
|
+
// src/scanner/scan/ai/providers/claude.ts
|
|
2904
2948
|
var CLAUDE_FILES = [
|
|
2905
2949
|
{ dest: ".claude/rules/uidex.md", template: "claude/rules.md" },
|
|
2906
|
-
{ dest: ".claude/commands/uidex/audit.md", template: "claude/audit.md" }
|
|
2950
|
+
{ dest: ".claude/commands/uidex/audit.md", template: "claude/audit.md" },
|
|
2951
|
+
{ dest: ".claude/commands/uidex/api.md", template: "claude/api.md" }
|
|
2907
2952
|
];
|
|
2908
2953
|
var claudeProvider = {
|
|
2909
2954
|
id: "claude",
|
|
2910
2955
|
label: "Claude Code",
|
|
2911
|
-
description: "Adds .claude/rules/uidex.md and
|
|
2956
|
+
description: "Adds .claude/rules/uidex.md, /uidex:audit, and /uidex:api slash commands.",
|
|
2912
2957
|
async install({ cwd, force }) {
|
|
2913
2958
|
const changes = [];
|
|
2914
2959
|
for (const file of CLAUDE_FILES) {
|
|
@@ -2956,13 +3001,13 @@ function cleanupEmpty(dir) {
|
|
|
2956
3001
|
}
|
|
2957
3002
|
}
|
|
2958
3003
|
|
|
2959
|
-
// src/scan/ai/providers/index.ts
|
|
3004
|
+
// src/scanner/scan/ai/providers/index.ts
|
|
2960
3005
|
var PROVIDERS = [claudeProvider];
|
|
2961
3006
|
function getProvider(id) {
|
|
2962
3007
|
return PROVIDERS.find((p2) => p2.id === id);
|
|
2963
3008
|
}
|
|
2964
3009
|
|
|
2965
|
-
// src/scan/ai/index.ts
|
|
3010
|
+
// src/scanner/scan/ai/index.ts
|
|
2966
3011
|
async function runAiCommand(opts) {
|
|
2967
3012
|
const { cwd, argv } = opts;
|
|
2968
3013
|
const sub = argv[0];
|
|
@@ -3073,8 +3118,8 @@ function err(exitCode, stderr) {
|
|
|
3073
3118
|
return { exitCode, stdout: "", stderr };
|
|
3074
3119
|
}
|
|
3075
3120
|
|
|
3076
|
-
// src/
|
|
3077
|
-
function
|
|
3121
|
+
// src/scanner/cli/parse-args.ts
|
|
3122
|
+
function parseArgs(args) {
|
|
3078
3123
|
const positional = [];
|
|
3079
3124
|
const flags = {};
|
|
3080
3125
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -3098,9 +3143,11 @@ function parseFlags2(args) {
|
|
|
3098
3143
|
}
|
|
3099
3144
|
return { positional, flags };
|
|
3100
3145
|
}
|
|
3146
|
+
|
|
3147
|
+
// src/scanner/scan/cli.ts
|
|
3101
3148
|
async function run(opts) {
|
|
3102
3149
|
const cwd = opts.cwd ?? process.cwd();
|
|
3103
|
-
const { positional, flags } =
|
|
3150
|
+
const { positional, flags } = parseArgs(opts.argv);
|
|
3104
3151
|
const command = positional[0] ?? "help";
|
|
3105
3152
|
const writer = createWriter();
|
|
3106
3153
|
try {
|
|
@@ -3144,6 +3191,10 @@ function helpText2() {
|
|
|
3144
3191
|
" scan [flags] Run the scanner pipeline",
|
|
3145
3192
|
" scaffold widget <id> Emit a Playwright spec from a widget's acceptance",
|
|
3146
3193
|
" ai <install|uninstall|providers> Manage AI assistant integrations",
|
|
3194
|
+
" api <METHOD> <PATH> Call the uidex API",
|
|
3195
|
+
" api --list Show available API routes",
|
|
3196
|
+
" api login Authenticate via browser",
|
|
3197
|
+
" api login --token <tok> Store an auth token directly",
|
|
3147
3198
|
"",
|
|
3148
3199
|
"Flags:",
|
|
3149
3200
|
" --check Verify the on-disk gen file matches a fresh scan; exit non-zero on drift (read-only)",
|