@decantr/cli 1.0.0-beta.2

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.
Files changed (2) hide show
  1. package/dist/index.js +225 -0
  2. package/package.json +30 -0
package/dist/index.js ADDED
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { readFileSync } from "fs";
5
+ import { join } from "path";
6
+ import { validateEssence, evaluateGuard } from "@decantr/essence-spec";
7
+ import { createResolver, createRegistryClient } from "@decantr/registry";
8
+ var BOLD = "\x1B[1m";
9
+ var DIM = "\x1B[2m";
10
+ var RESET = "\x1B[0m";
11
+ var RED = "\x1B[31m";
12
+ var GREEN = "\x1B[32m";
13
+ var CYAN = "\x1B[36m";
14
+ var YELLOW = "\x1B[33m";
15
+ function heading(text) {
16
+ return `
17
+ ${BOLD}${text}${RESET}
18
+ `;
19
+ }
20
+ function success(text) {
21
+ return `${GREEN}${text}${RESET}`;
22
+ }
23
+ function error(text) {
24
+ return `${RED}${text}${RESET}`;
25
+ }
26
+ function dim(text) {
27
+ return `${DIM}${text}${RESET}`;
28
+ }
29
+ function cyan(text) {
30
+ return `${CYAN}${text}${RESET}`;
31
+ }
32
+ function getContentRoot() {
33
+ const bundled = join(import.meta.dirname, "..", "..", "..", "content");
34
+ return process.env.DECANTR_CONTENT_ROOT || bundled;
35
+ }
36
+ function getResolver() {
37
+ return createResolver({ contentRoot: getContentRoot() });
38
+ }
39
+ async function cmdSearch(query, type) {
40
+ const client = createRegistryClient();
41
+ const results = await client.search(query, type);
42
+ if (results.length === 0) {
43
+ console.log(dim(`No results for "${query}"`));
44
+ return;
45
+ }
46
+ console.log(heading(`${results.length} result(s) for "${query}"`));
47
+ for (const r of results) {
48
+ console.log(` ${cyan(r.type.padEnd(12))} ${BOLD}${r.id}${RESET}`);
49
+ console.log(` ${dim(r.description || "")}`);
50
+ console.log("");
51
+ }
52
+ }
53
+ async function cmdGet(type, id) {
54
+ const validTypes = ["pattern", "archetype", "recipe", "theme", "blueprint"];
55
+ if (!validTypes.includes(type)) {
56
+ console.error(error(`Invalid type "${type}". Must be one of: ${validTypes.join(", ")}`));
57
+ process.exitCode = 1;
58
+ return;
59
+ }
60
+ const resolver = getResolver();
61
+ const result = await resolver.resolve(type, id);
62
+ if (!result) {
63
+ console.error(error(`${type} "${id}" not found.`));
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+ console.log(JSON.stringify(result.item, null, 2));
68
+ }
69
+ async function cmdValidate(path) {
70
+ const essencePath = path || join(process.cwd(), "decantr.essence.json");
71
+ let raw;
72
+ try {
73
+ raw = readFileSync(essencePath, "utf-8");
74
+ } catch {
75
+ console.error(error(`Could not read ${essencePath}`));
76
+ process.exitCode = 1;
77
+ return;
78
+ }
79
+ let essence;
80
+ try {
81
+ essence = JSON.parse(raw);
82
+ } catch (e) {
83
+ console.error(error(`Invalid JSON: ${e.message}`));
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+ const result = validateEssence(essence);
88
+ if (result.valid) {
89
+ console.log(success("Essence is valid."));
90
+ } else {
91
+ console.error(error("Validation failed:"));
92
+ for (const err of result.errors) {
93
+ console.error(` ${RED}${err}${RESET}`);
94
+ }
95
+ process.exitCode = 1;
96
+ }
97
+ try {
98
+ const violations = evaluateGuard(essence, {});
99
+ if (violations.length > 0) {
100
+ console.log(heading("Guard violations:"));
101
+ for (const v of violations) {
102
+ const vr = v;
103
+ console.log(` ${YELLOW}[${vr.rule}]${RESET} ${vr.message}`);
104
+ }
105
+ } else if (result.valid) {
106
+ console.log(success("No guard violations."));
107
+ }
108
+ } catch {
109
+ }
110
+ }
111
+ async function cmdList(type) {
112
+ const validTypes = ["patterns", "archetypes", "recipes", "themes", "blueprints"];
113
+ if (!validTypes.includes(type)) {
114
+ console.error(error(`Invalid type "${type}". Must be one of: ${validTypes.join(", ")}`));
115
+ process.exitCode = 1;
116
+ return;
117
+ }
118
+ const { readdirSync } = await import("fs");
119
+ const dir = join(getContentRoot(), type);
120
+ try {
121
+ const files = readdirSync(dir).filter((f) => f.endsWith(".json"));
122
+ console.log(heading(`${files.length} ${type}`));
123
+ for (const f of files) {
124
+ const data = JSON.parse(readFileSync(join(dir, f), "utf-8"));
125
+ console.log(` ${cyan(data.id || f.replace(".json", ""))} ${dim(data.description || data.name || "")}`);
126
+ }
127
+ } catch {
128
+ const coreDir = join(getContentRoot(), "core", type);
129
+ try {
130
+ const files = readdirSync(coreDir).filter((f) => f.endsWith(".json"));
131
+ console.log(heading(`${files.length} ${type} (core)`));
132
+ for (const f of files) {
133
+ const data = JSON.parse(readFileSync(join(coreDir, f), "utf-8"));
134
+ console.log(` ${cyan(data.id || f.replace(".json", ""))} ${dim(data.description || data.name || "")}`);
135
+ }
136
+ } catch {
137
+ console.log(dim(`No ${type} found.`));
138
+ }
139
+ }
140
+ }
141
+ function cmdHelp() {
142
+ console.log(`
143
+ ${BOLD}decantr${RESET} \u2014 Design intelligence for AI-generated UI
144
+
145
+ ${BOLD}Usage:${RESET}
146
+ decantr search <query> [--type pattern|archetype|recipe|theme]
147
+ decantr get <type> <id>
148
+ decantr list <type>
149
+ decantr validate [path]
150
+ decantr help
151
+
152
+ ${BOLD}Commands:${RESET}
153
+ ${cyan("search")} Search the registry for patterns, archetypes, recipes, themes
154
+ ${cyan("get")} Get full details of a registry item as JSON
155
+ ${cyan("list")} List all items of a type (patterns, archetypes, recipes, themes, blueprints)
156
+ ${cyan("validate")} Validate a decantr.essence.json file against the schema and guard rules
157
+ ${cyan("help")} Show this help message
158
+
159
+ ${BOLD}Examples:${RESET}
160
+ decantr search dashboard
161
+ decantr search kpi --type pattern
162
+ decantr get pattern kpi-grid
163
+ decantr get recipe luminarum
164
+ decantr get theme luminarum
165
+ decantr list patterns
166
+ decantr list themes
167
+ decantr validate
168
+ decantr validate ./my-project/decantr.essence.json
169
+ `);
170
+ }
171
+ async function main() {
172
+ const args = process.argv.slice(2);
173
+ const command = args[0];
174
+ if (!command || command === "help" || command === "--help" || command === "-h") {
175
+ cmdHelp();
176
+ return;
177
+ }
178
+ switch (command) {
179
+ case "search": {
180
+ const query = args[1];
181
+ if (!query) {
182
+ console.error(error("Usage: decantr search <query> [--type <type>]"));
183
+ process.exitCode = 1;
184
+ return;
185
+ }
186
+ const typeIdx = args.indexOf("--type");
187
+ const type = typeIdx !== -1 ? args[typeIdx + 1] : void 0;
188
+ await cmdSearch(query, type);
189
+ break;
190
+ }
191
+ case "get": {
192
+ const type = args[1];
193
+ const id = args[2];
194
+ if (!type || !id) {
195
+ console.error(error("Usage: decantr get <type> <id>"));
196
+ process.exitCode = 1;
197
+ return;
198
+ }
199
+ await cmdGet(type, id);
200
+ break;
201
+ }
202
+ case "list": {
203
+ const type = args[1];
204
+ if (!type) {
205
+ console.error(error("Usage: decantr list <type>"));
206
+ process.exitCode = 1;
207
+ return;
208
+ }
209
+ await cmdList(type);
210
+ break;
211
+ }
212
+ case "validate": {
213
+ await cmdValidate(args[1]);
214
+ break;
215
+ }
216
+ default:
217
+ console.error(error(`Unknown command: ${command}`));
218
+ cmdHelp();
219
+ process.exitCode = 1;
220
+ }
221
+ }
222
+ main().catch((e) => {
223
+ console.error(error(e.message));
224
+ process.exitCode = 1;
225
+ });
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@decantr/cli",
3
+ "version": "1.0.0-beta.2",
4
+ "description": "Decantr CLI — search the registry, validate essence files, and access design intelligence from the terminal",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/decantr-ai/decantr.git",
9
+ "directory": "packages/cli"
10
+ },
11
+ "homepage": "https://decantr.ai",
12
+ "type": "module",
13
+ "bin": {
14
+ "decantr": "./dist/index.js"
15
+ },
16
+ "main": "dist/index.js",
17
+ "files": ["dist"],
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest"
25
+ },
26
+ "dependencies": {
27
+ "@decantr/essence-spec": "workspace:*",
28
+ "@decantr/registry": "workspace:*"
29
+ }
30
+ }