@anatolykoptev/krolik-cli 0.10.0 → 0.11.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/README.md +22 -2
- package/dist/bin/cli.js +143 -32
- package/dist/bin/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,12 +39,14 @@ One command replaces 10+ manual searches. AI gets complete project context insta
|
|
|
39
39
|
```bash
|
|
40
40
|
krolik context --feature auth # Everything about auth feature
|
|
41
41
|
krolik context --issue 42 # Context from GitHub issue
|
|
42
|
+
krolik context --search "tRPC" # Find code matching pattern
|
|
43
|
+
krolik context --changed-only # Only git-changed files
|
|
42
44
|
krolik context --minimal # Ultra-compact (~1500 tokens)
|
|
43
45
|
krolik context --quick # Compact with repo-map (~3500 tokens)
|
|
44
46
|
krolik context --deep # Full analysis (~5s)
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
**What it collects**: git state, database schema, API routes, project structure, types, past decisions, library docs.
|
|
49
|
+
**What it collects**: git state, database schema, API routes, project structure, types, past decisions, library docs, lib modules with signatures.
|
|
48
50
|
|
|
49
51
|
---
|
|
50
52
|
|
|
@@ -69,7 +71,10 @@ Memories are automatically included in context — AI sees what was decided befo
|
|
|
69
71
|
Analyzes entire codebase and creates a prioritized report.
|
|
70
72
|
|
|
71
73
|
```bash
|
|
72
|
-
krolik audit
|
|
74
|
+
krolik audit # All issues
|
|
75
|
+
krolik audit --mode release # Security + type-safety
|
|
76
|
+
krolik audit --mode queries # Duplicate Prisma/tRPC queries
|
|
77
|
+
krolik audit --mode pre-commit # Quick check before commit
|
|
73
78
|
```
|
|
74
79
|
|
|
75
80
|
**Output**: `.krolik/AI-REPORT.md` with issues ranked by severity, files with most problems, and quick wins that can be auto-fixed.
|
|
@@ -133,6 +138,21 @@ krolik docs list # List cached libraries
|
|
|
133
138
|
|
|
134
139
|
---
|
|
135
140
|
|
|
141
|
+
### `krolik modules` — Query Lib Modules
|
|
142
|
+
|
|
143
|
+
Discover reusable utilities in your codebase before writing new code.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
krolik modules # List all lib modules
|
|
147
|
+
krolik modules --search parse # Search exports by name
|
|
148
|
+
krolik modules --get fs # Details of specific module
|
|
149
|
+
krolik modules --paths # Show where modules are found
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**What it shows**: functions with signatures, types, constants — everything exported from `lib/@*` directories.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
136
156
|
### Other Commands
|
|
137
157
|
|
|
138
158
|
| Command | What it does |
|
package/dist/bin/cli.js
CHANGED
|
@@ -56,7 +56,7 @@ var KROLIK_VERSION, TEMPLATE_VERSION;
|
|
|
56
56
|
var init_version = __esm({
|
|
57
57
|
"src/version.ts"() {
|
|
58
58
|
init_esm_shims();
|
|
59
|
-
KROLIK_VERSION = "0.
|
|
59
|
+
KROLIK_VERSION = "0.11.0";
|
|
60
60
|
TEMPLATE_VERSION = "6.1.0";
|
|
61
61
|
}
|
|
62
62
|
});
|
|
@@ -13325,18 +13325,38 @@ var init_schema2 = __esm({
|
|
|
13325
13325
|
init_esm_shims();
|
|
13326
13326
|
init_core();
|
|
13327
13327
|
schemaFlagSchema = {
|
|
13328
|
-
json: COMMON_FLAGS.json
|
|
13328
|
+
json: COMMON_FLAGS.json,
|
|
13329
|
+
model: { flag: "--model" },
|
|
13330
|
+
domain: { flag: "--domain" },
|
|
13331
|
+
compact: { flag: "--compact" }
|
|
13329
13332
|
};
|
|
13330
13333
|
schemaTool = {
|
|
13331
13334
|
name: "krolik_schema",
|
|
13332
|
-
description:
|
|
13335
|
+
description: `Analyze Prisma database schema. Returns models, fields, relations, and enums.
|
|
13336
|
+
|
|
13337
|
+
**For large schemas**, use compact mode or filters to reduce output:
|
|
13338
|
+
- compact: true - shows only model names with relations (no field details)
|
|
13339
|
+
- model: "User" - filter by model name (partial match)
|
|
13340
|
+
- domain: "Auth" - filter by domain (derived from schema filename)`,
|
|
13333
13341
|
inputSchema: {
|
|
13334
13342
|
type: "object",
|
|
13335
13343
|
properties: {
|
|
13336
13344
|
...PROJECT_PROPERTY,
|
|
13337
13345
|
json: {
|
|
13338
13346
|
type: "boolean",
|
|
13339
|
-
description: "Return JSON format instead of
|
|
13347
|
+
description: "Return JSON format instead of XML"
|
|
13348
|
+
},
|
|
13349
|
+
model: {
|
|
13350
|
+
type: "string",
|
|
13351
|
+
description: 'Filter by model name (partial match, case-insensitive). Example: "User", "Booking"'
|
|
13352
|
+
},
|
|
13353
|
+
domain: {
|
|
13354
|
+
type: "string",
|
|
13355
|
+
description: 'Filter by domain (derived from schema filename). Example: "Auth", "Bookings", "CRM"'
|
|
13356
|
+
},
|
|
13357
|
+
compact: {
|
|
13358
|
+
type: "boolean",
|
|
13359
|
+
description: "Compact output - models with relations only, no field details. Recommended for large schemas."
|
|
13340
13360
|
}
|
|
13341
13361
|
}
|
|
13342
13362
|
},
|
|
@@ -39602,34 +39622,24 @@ function groupByDomain3(models) {
|
|
|
39602
39622
|
return groupBy(models, (model) => inferDomain(model.file));
|
|
39603
39623
|
}
|
|
39604
39624
|
function inferDomain(filename) {
|
|
39605
|
-
const base = filename.replace(
|
|
39606
|
-
|
|
39607
|
-
|
|
39608
|
-
|
|
39609
|
-
|
|
39610
|
-
|
|
39611
|
-
|
|
39625
|
+
const base = filename.replace(/\.prisma$/, "").replace(/^.*\//, "");
|
|
39626
|
+
if (!base) return "Other";
|
|
39627
|
+
const parts = base.split(/[-_]/);
|
|
39628
|
+
const formatted = parts.map((part) => {
|
|
39629
|
+
const lower = part.toLowerCase();
|
|
39630
|
+
if (UPPERCASE_ABBREVS.includes(lower)) {
|
|
39631
|
+
return lower.toUpperCase();
|
|
39632
|
+
}
|
|
39633
|
+
return part.charAt(0).toUpperCase() + part.slice(1).toLowerCase();
|
|
39634
|
+
});
|
|
39635
|
+
return formatted.join(" ");
|
|
39612
39636
|
}
|
|
39613
|
-
var
|
|
39637
|
+
var UPPERCASE_ABBREVS;
|
|
39614
39638
|
var init_grouping4 = __esm({
|
|
39615
39639
|
"src/commands/schema/grouping.ts"() {
|
|
39616
39640
|
init_esm_shims();
|
|
39617
39641
|
init_core2();
|
|
39618
|
-
|
|
39619
|
-
auth: "Authentication",
|
|
39620
|
-
user: "Users",
|
|
39621
|
-
content: "Content",
|
|
39622
|
-
booking: "Bookings",
|
|
39623
|
-
event: "Events",
|
|
39624
|
-
ticket: "Ticketing",
|
|
39625
|
-
business: "Business",
|
|
39626
|
-
social: "Social",
|
|
39627
|
-
gamification: "Gamification",
|
|
39628
|
-
payment: "Payments",
|
|
39629
|
-
notification: "Notifications",
|
|
39630
|
-
integration: "Integrations",
|
|
39631
|
-
system: "System"
|
|
39632
|
-
};
|
|
39642
|
+
UPPERCASE_ABBREVS = ["crm", "api", "ugc", "sso", "oauth", "jwt", "sql"];
|
|
39633
39643
|
}
|
|
39634
39644
|
});
|
|
39635
39645
|
|
|
@@ -39756,6 +39766,60 @@ function formatMarkdown3(data) {
|
|
|
39756
39766
|
lines.push("*Generated by krolik-cli*");
|
|
39757
39767
|
return lines.join("\n");
|
|
39758
39768
|
}
|
|
39769
|
+
function formatCompact(data, fullData) {
|
|
39770
|
+
const lines = [];
|
|
39771
|
+
const total = fullData ?? data;
|
|
39772
|
+
const isFiltered = fullData && data.modelCount !== fullData.modelCount;
|
|
39773
|
+
lines.push('<prisma-schema mode="compact">');
|
|
39774
|
+
if (isFiltered) {
|
|
39775
|
+
lines.push(
|
|
39776
|
+
` <stats models="${data.modelCount}" enums="${data.enumCount}" filtered="true" total-models="${total.modelCount}" total-enums="${total.enumCount}" />`
|
|
39777
|
+
);
|
|
39778
|
+
} else {
|
|
39779
|
+
lines.push(` <stats models="${data.modelCount}" enums="${data.enumCount}" />`);
|
|
39780
|
+
}
|
|
39781
|
+
const byDomain = groupByDomain3(data.models);
|
|
39782
|
+
const domains = Array.from(byDomain.keys()).sort();
|
|
39783
|
+
lines.push(` <domains>${domains.join(", ")}</domains>`);
|
|
39784
|
+
lines.push("");
|
|
39785
|
+
for (const [domain, models] of byDomain) {
|
|
39786
|
+
const modelCount = models.length;
|
|
39787
|
+
lines.push(` <domain name="${domain}" models="${modelCount}">`);
|
|
39788
|
+
for (const model of models) {
|
|
39789
|
+
const relStr = model.relations.length > 0 ? ` relations="${model.relations.join(", ")}"` : "";
|
|
39790
|
+
const keyFields = model.fields.filter((f) => f.isId || f.isUnique || f.name.endsWith("Id"));
|
|
39791
|
+
const keyFieldNames = keyFields.map((f) => f.name).slice(0, 5);
|
|
39792
|
+
const keyStr = keyFieldNames.length > 0 ? ` keys="${keyFieldNames.join(", ")}"` : "";
|
|
39793
|
+
lines.push(
|
|
39794
|
+
` <model name="${model.name}" fields="${model.fields.length}"${relStr}${keyStr} />`
|
|
39795
|
+
);
|
|
39796
|
+
}
|
|
39797
|
+
lines.push(" </domain>");
|
|
39798
|
+
}
|
|
39799
|
+
if (data.enums.length > 0) {
|
|
39800
|
+
lines.push("");
|
|
39801
|
+
lines.push(` <enums count="${data.enums.length}">`);
|
|
39802
|
+
const enumNames = data.enums.map((e) => e.name).sort();
|
|
39803
|
+
if (enumNames.length > 20) {
|
|
39804
|
+
const byPrefix = /* @__PURE__ */ new Map();
|
|
39805
|
+
for (const name of enumNames) {
|
|
39806
|
+
const prefix = name.replace(/[A-Z][a-z]+$/, "").replace(/Status$|Type$|Role$|State$/, "") || "General";
|
|
39807
|
+
if (!byPrefix.has(prefix)) byPrefix.set(prefix, []);
|
|
39808
|
+
byPrefix.get(prefix).push(name);
|
|
39809
|
+
}
|
|
39810
|
+
for (const [prefix, names] of byPrefix) {
|
|
39811
|
+
lines.push(` <group prefix="${prefix}">${names.join(", ")}</group>`);
|
|
39812
|
+
}
|
|
39813
|
+
} else {
|
|
39814
|
+
lines.push(` ${enumNames.join(", ")}`);
|
|
39815
|
+
}
|
|
39816
|
+
lines.push(" </enums>");
|
|
39817
|
+
}
|
|
39818
|
+
lines.push("");
|
|
39819
|
+
lines.push(' <hint>Use --model "Name" or --domain "Domain" for details</hint>');
|
|
39820
|
+
lines.push("</prisma-schema>");
|
|
39821
|
+
return lines.join("\n");
|
|
39822
|
+
}
|
|
39759
39823
|
var init_output7 = __esm({
|
|
39760
39824
|
"src/commands/schema/output.ts"() {
|
|
39761
39825
|
init_esm_shims();
|
|
@@ -39800,6 +39864,29 @@ function findSchemaDir2(projectRoot, configSchemaDir) {
|
|
|
39800
39864
|
}
|
|
39801
39865
|
return null;
|
|
39802
39866
|
}
|
|
39867
|
+
function filterSchema(result, options) {
|
|
39868
|
+
let { models, enums } = result;
|
|
39869
|
+
if (options.domain) {
|
|
39870
|
+
const domainLower = options.domain.toLowerCase();
|
|
39871
|
+
const byDomain = groupByDomain3(models);
|
|
39872
|
+
const matchingDomain = Array.from(byDomain.keys()).find((d) => d.toLowerCase() === domainLower);
|
|
39873
|
+
if (matchingDomain) {
|
|
39874
|
+
models = byDomain.get(matchingDomain) ?? [];
|
|
39875
|
+
} else {
|
|
39876
|
+
models = [];
|
|
39877
|
+
}
|
|
39878
|
+
}
|
|
39879
|
+
if (options.model) {
|
|
39880
|
+
const modelLower = options.model.toLowerCase();
|
|
39881
|
+
models = models.filter((m) => m.name.toLowerCase().includes(modelLower));
|
|
39882
|
+
}
|
|
39883
|
+
return {
|
|
39884
|
+
models,
|
|
39885
|
+
enums,
|
|
39886
|
+
modelCount: models.length,
|
|
39887
|
+
enumCount: enums.length
|
|
39888
|
+
};
|
|
39889
|
+
}
|
|
39803
39890
|
async function runSchema(ctx) {
|
|
39804
39891
|
const { config, logger: logger2, options } = ctx;
|
|
39805
39892
|
const schemaDir = findSchemaDir2(config.projectRoot, config.prisma?.schemaDir);
|
|
@@ -39808,9 +39895,11 @@ async function runSchema(ctx) {
|
|
|
39808
39895
|
logger2.info("Checked: prisma, packages/db/prisma, src/prisma, db/prisma");
|
|
39809
39896
|
return;
|
|
39810
39897
|
}
|
|
39811
|
-
const
|
|
39898
|
+
const fullResult = analyzeSchema(schemaDir);
|
|
39899
|
+
const hasFilters = options.model || options.domain;
|
|
39900
|
+
const result = hasFilters ? filterSchema(fullResult, options) : fullResult;
|
|
39812
39901
|
const format2 = options.format ?? "ai";
|
|
39813
|
-
const xmlOutput = formatAI3(
|
|
39902
|
+
const xmlOutput = formatAI3(fullResult);
|
|
39814
39903
|
saveKrolikFile(config.projectRoot, "SCHEMA.xml", xmlOutput);
|
|
39815
39904
|
if (options.save) {
|
|
39816
39905
|
const md = formatMarkdown3(result);
|
|
@@ -39831,12 +39920,17 @@ async function runSchema(ctx) {
|
|
|
39831
39920
|
printSchema(result, logger2, options.groupBy ?? "file");
|
|
39832
39921
|
return;
|
|
39833
39922
|
}
|
|
39834
|
-
|
|
39923
|
+
if (options.compact) {
|
|
39924
|
+
console.log(formatCompact(result, fullResult));
|
|
39925
|
+
return;
|
|
39926
|
+
}
|
|
39927
|
+
console.log(hasFilters ? formatAI3(result) : xmlOutput);
|
|
39835
39928
|
}
|
|
39836
39929
|
var init_schema3 = __esm({
|
|
39837
39930
|
"src/commands/schema/index.ts"() {
|
|
39838
39931
|
init_esm_shims();
|
|
39839
39932
|
init_fs2();
|
|
39933
|
+
init_grouping4();
|
|
39840
39934
|
init_output7();
|
|
39841
39935
|
init_parser2();
|
|
39842
39936
|
}
|
|
@@ -59082,10 +59176,27 @@ function registerRoutesCommand(program) {
|
|
|
59082
59176
|
// src/cli/commands/schema.ts
|
|
59083
59177
|
init_esm_shims();
|
|
59084
59178
|
function registerSchemaCommand(program) {
|
|
59085
|
-
program.command("schema").description("Analyze Prisma schema").option("--save", "Save to SCHEMA.md").
|
|
59179
|
+
program.command("schema").description("Analyze Prisma schema").option("--save", "Save to SCHEMA.md").option("-m, --model <name>", "Filter by model name (partial match)").option("-d, --domain <name>", "Filter by domain name").option("-c, --compact", "Compact output (models with relations only, no field details)").addHelpText(
|
|
59180
|
+
"after",
|
|
59181
|
+
`
|
|
59182
|
+
Examples:
|
|
59183
|
+
krolik schema # Full schema (may be large)
|
|
59184
|
+
krolik schema --compact # Compact view - just models and relations
|
|
59185
|
+
krolik schema --domain Bookings # Only Bookings domain
|
|
59186
|
+
krolik schema --model User # Only models containing "User"
|
|
59187
|
+
`
|
|
59188
|
+
).action(async (options) => {
|
|
59086
59189
|
const { runSchema: runSchema2 } = await Promise.resolve().then(() => (init_schema3(), schema_exports));
|
|
59087
59190
|
const ctx = await createContext3(program, options);
|
|
59088
|
-
await runSchema2(
|
|
59191
|
+
await runSchema2({
|
|
59192
|
+
...ctx,
|
|
59193
|
+
options: {
|
|
59194
|
+
...ctx.options,
|
|
59195
|
+
model: options.model,
|
|
59196
|
+
domain: options.domain,
|
|
59197
|
+
compact: options.compact
|
|
59198
|
+
}
|
|
59199
|
+
});
|
|
59089
59200
|
});
|
|
59090
59201
|
}
|
|
59091
59202
|
|