@decantr/cli 1.3.0 → 1.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/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import "./chunk-2F6Q5S5W.js";
2
- import "./chunk-CT5XHG6I.js";
1
+ import "./chunk-SUNMRG3P.js";
2
+ import "./chunk-6K6ZPDT4.js";
@@ -0,0 +1,131 @@
1
+ import {
2
+ RegistryClient,
3
+ refreshDerivedFiles
4
+ } from "./chunk-6K6ZPDT4.js";
5
+
6
+ // src/commands/upgrade.ts
7
+ import { readFileSync, writeFileSync, existsSync } from "fs";
8
+ import { join } from "path";
9
+ import { isV3 } from "@decantr/essence-spec";
10
+ var GREEN = "\x1B[32m";
11
+ var YELLOW = "\x1B[33m";
12
+ var RESET = "\x1B[0m";
13
+ var DIM = "\x1B[2m";
14
+ var CYAN = "\x1B[36m";
15
+ async function cmdUpgrade(projectRoot = process.cwd(), options = {}) {
16
+ const essencePath = join(projectRoot, "decantr.essence.json");
17
+ if (!existsSync(essencePath)) {
18
+ console.error("No decantr.essence.json found. Run `decantr init` first.");
19
+ process.exitCode = 1;
20
+ return;
21
+ }
22
+ const essence = JSON.parse(readFileSync(essencePath, "utf-8"));
23
+ const client = new RegistryClient({
24
+ cacheDir: join(projectRoot, ".decantr", "cache"),
25
+ projectRoot
26
+ });
27
+ console.log("Checking for updates...\n");
28
+ const upgrades = [];
29
+ const themeStyle = essence.dna?.theme?.style || essence.theme?.style;
30
+ if (themeStyle) {
31
+ const theme = await client.fetchTheme(themeStyle);
32
+ if (theme) {
33
+ const themeData = theme.data;
34
+ const inner = themeData.data ?? themeData;
35
+ const latestVersion = inner.version || themeData.version;
36
+ if (latestVersion) {
37
+ const current = essence.dna?.theme?.version || essence.theme?.version || "0.0.0";
38
+ if (latestVersion !== current) {
39
+ upgrades.push({
40
+ type: "theme",
41
+ id: themeStyle,
42
+ currentVersion: current,
43
+ latestVersion,
44
+ data: themeData
45
+ });
46
+ }
47
+ }
48
+ }
49
+ }
50
+ if (essence.blueprint && typeof essence.blueprint === "string") {
51
+ const blueprint = await client.fetchBlueprint(essence.blueprint);
52
+ if (blueprint) {
53
+ const bpData = blueprint.data;
54
+ const inner = bpData.data ?? bpData;
55
+ const latestVersion = inner.version || bpData.version;
56
+ if (latestVersion) {
57
+ const current = essence.blueprintVersion || "0.0.0";
58
+ if (latestVersion !== current) {
59
+ upgrades.push({
60
+ type: "blueprint",
61
+ id: essence.blueprint,
62
+ currentVersion: current,
63
+ latestVersion,
64
+ data: bpData
65
+ });
66
+ }
67
+ }
68
+ }
69
+ }
70
+ if (upgrades.length === 0) {
71
+ console.log(`${GREEN}Everything is up to date.${RESET}`);
72
+ return;
73
+ }
74
+ console.log("Available upgrades:\n");
75
+ for (const u of upgrades) {
76
+ console.log(` ${u.type}/${u.id}: ${DIM}${u.currentVersion}${RESET} -> ${GREEN}${u.latestVersion}${RESET}`);
77
+ }
78
+ if (!options.apply) {
79
+ console.log(`
80
+ ${YELLOW}Run with --apply to apply upgrades.${RESET}`);
81
+ return;
82
+ }
83
+ console.log(`
84
+ ${CYAN}Applying upgrades...${RESET}
85
+ `);
86
+ let essenceModified = false;
87
+ for (const upgrade of upgrades) {
88
+ console.log(` Updating ${upgrade.type}/${upgrade.id} to ${upgrade.latestVersion}...`);
89
+ switch (upgrade.type) {
90
+ case "theme": {
91
+ await client.fetchTheme(upgrade.id);
92
+ if (essence.dna?.theme) {
93
+ essence.dna.theme.version = upgrade.latestVersion;
94
+ essenceModified = true;
95
+ } else if (essence.theme) {
96
+ essence.theme.version = upgrade.latestVersion;
97
+ essenceModified = true;
98
+ }
99
+ console.log(` ${GREEN}Theme cache updated.${RESET}`);
100
+ break;
101
+ }
102
+ case "blueprint": {
103
+ await client.fetchBlueprint(upgrade.id);
104
+ essence.blueprintVersion = upgrade.latestVersion;
105
+ essenceModified = true;
106
+ console.log(` ${GREEN}Blueprint cache updated.${RESET}`);
107
+ break;
108
+ }
109
+ }
110
+ }
111
+ if (essenceModified) {
112
+ writeFileSync(essencePath, JSON.stringify(essence, null, 2) + "\n");
113
+ console.log(`
114
+ ${GREEN}Essence file updated.${RESET}`);
115
+ }
116
+ if (isV3(essence)) {
117
+ console.log(`
118
+ Regenerating context files...`);
119
+ try {
120
+ const result = await refreshDerivedFiles(projectRoot, essence, client);
121
+ console.log(` ${GREEN}Updated ${result.contextFiles.length} context file(s) and ${result.cssFiles.length} CSS file(s).${RESET}`);
122
+ } catch (e) {
123
+ console.log(` ${YELLOW}Warning: Could not regenerate context files: ${e.message}${RESET}`);
124
+ }
125
+ }
126
+ console.log(`
127
+ ${GREEN}All upgrades applied.${RESET}`);
128
+ }
129
+ export {
130
+ cmdUpgrade
131
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decantr/cli",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Decantr CLI — search the registry, validate essence files, and access design intelligence from the terminal",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -23,8 +23,8 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@decantr/essence-spec": "1.0.0-beta.6",
27
- "@decantr/registry": "1.0.0-beta.6"
26
+ "@decantr/essence-spec": "1.0.0-beta.8",
27
+ "@decantr/registry": "1.0.0-beta.8"
28
28
  },
29
29
  "scripts": {
30
30
  "build": "tsup",
@@ -1,203 +0,0 @@
1
- // src/registry.ts
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from "fs";
3
- import { join } from "path";
4
- import { RegistryAPIClient } from "@decantr/registry";
5
- var DEFAULT_API_URL = "https://api.decantr.ai/v1";
6
- var ALL_CONTENT_TYPES = ["themes", "patterns", "recipes", "blueprints", "archetypes", "shells"];
7
- function loadFromCache(cacheDir, contentType, id, namespace) {
8
- const nsDir = namespace ? join(cacheDir, namespace) : cacheDir;
9
- const cachePath = id ? join(nsDir, contentType, `${id}.json`) : join(nsDir, contentType, "index.json");
10
- if (!existsSync(cachePath)) return null;
11
- try {
12
- const data = JSON.parse(readFileSync(cachePath, "utf-8"));
13
- return { data, source: { type: "cache" } };
14
- } catch {
15
- return null;
16
- }
17
- }
18
- function saveToCache(cacheDir, contentType, id, data, namespace = "@official") {
19
- const dir = join(cacheDir, namespace, contentType);
20
- mkdirSync(dir, { recursive: true });
21
- const cachePath = id ? join(dir, `${id}.json`) : join(dir, "index.json");
22
- writeFileSync(cachePath, JSON.stringify(data, null, 2));
23
- }
24
- var RegistryClient = class {
25
- cacheDir;
26
- apiUrl;
27
- offline;
28
- projectRoot;
29
- apiClient;
30
- constructor(options = {}) {
31
- this.projectRoot = options.projectRoot || process.cwd();
32
- this.cacheDir = options.cacheDir || join(this.projectRoot, ".decantr", "cache");
33
- this.apiUrl = options.apiUrl || DEFAULT_API_URL;
34
- this.offline = options.offline || false;
35
- this.apiClient = new RegistryAPIClient({
36
- baseUrl: this.apiUrl,
37
- apiKey: options.apiKey
38
- });
39
- }
40
- /**
41
- * Load content from .decantr/custom/{contentType}/{id}.json
42
- * Works for ALL content types, not just themes.
43
- */
44
- loadCustomContent(contentType, id) {
45
- const customPath = join(
46
- this.projectRoot,
47
- ".decantr",
48
- "custom",
49
- contentType,
50
- `${id}.json`
51
- );
52
- if (!existsSync(customPath)) return null;
53
- try {
54
- const data = JSON.parse(readFileSync(customPath, "utf-8"));
55
- return { data, source: { type: "custom", path: customPath } };
56
- } catch {
57
- return null;
58
- }
59
- }
60
- /**
61
- * List all custom content of a given type from .decantr/custom/{type}/
62
- */
63
- listCustomContent(contentType) {
64
- const dir = join(this.projectRoot, ".decantr", "custom", contentType);
65
- if (!existsSync(dir)) return [];
66
- try {
67
- return readdirSync(dir).filter((f) => f.endsWith(".json")).map((f) => {
68
- const data = JSON.parse(readFileSync(join(dir, f), "utf-8"));
69
- return { id: data.id || f.replace(".json", ""), ...data };
70
- });
71
- } catch {
72
- return [];
73
- }
74
- }
75
- /**
76
- * Unified fetch for a content list.
77
- * Resolution: API -> Cache. Custom items are merged into the list.
78
- */
79
- async fetchContentList(contentType, namespace) {
80
- let apiItems = [];
81
- let source = { type: "cache" };
82
- if (!this.offline) {
83
- try {
84
- const apiResult = await this.apiClient.listContent(contentType, { namespace });
85
- apiItems = apiResult.items;
86
- source = { type: "api", url: this.apiUrl };
87
- saveToCache(this.cacheDir, contentType, null, apiResult, namespace || "@official");
88
- } catch {
89
- }
90
- }
91
- if (apiItems.length === 0) {
92
- const cacheResult = loadFromCache(
93
- this.cacheDir,
94
- contentType,
95
- void 0,
96
- namespace
97
- );
98
- if (cacheResult) {
99
- apiItems = cacheResult.data.items;
100
- source = { type: "cache" };
101
- }
102
- }
103
- const customItems = this.listCustomContent(contentType);
104
- const allItems = [...customItems, ...apiItems];
105
- return {
106
- data: { items: allItems, total: allItems.length },
107
- source
108
- };
109
- }
110
- /**
111
- * Unified fetch for a single content item.
112
- * Resolution: Custom -> API -> Cache
113
- */
114
- async fetchContentItem(contentType, id, namespace = "@official") {
115
- const customId = id.startsWith("custom:") ? id.slice(7) : id;
116
- const customResult = this.loadCustomContent(contentType, customId);
117
- if (customResult) return customResult;
118
- if (id.startsWith("custom:")) return null;
119
- if (!this.offline) {
120
- try {
121
- const data = await this.apiClient.getContent(contentType, namespace, id);
122
- saveToCache(this.cacheDir, contentType, id, data, namespace);
123
- return { data, source: { type: "api", url: this.apiUrl } };
124
- } catch {
125
- }
126
- }
127
- return loadFromCache(this.cacheDir, contentType, id, namespace);
128
- }
129
- // ── Convenience methods (delegate to unified fetch) ──
130
- async fetchArchetypes() {
131
- return this.fetchContentList("archetypes");
132
- }
133
- async fetchArchetype(id) {
134
- return this.fetchContentItem("archetypes", id);
135
- }
136
- async fetchBlueprints() {
137
- return this.fetchContentList("blueprints");
138
- }
139
- async fetchBlueprint(id) {
140
- return this.fetchContentItem("blueprints", id);
141
- }
142
- async fetchThemes() {
143
- return this.fetchContentList("themes");
144
- }
145
- async fetchTheme(id) {
146
- return this.fetchContentItem("themes", id);
147
- }
148
- async fetchPatterns() {
149
- return this.fetchContentList("patterns");
150
- }
151
- async fetchPattern(id) {
152
- return this.fetchContentItem("patterns", id);
153
- }
154
- async fetchShells() {
155
- return this.fetchContentList("shells");
156
- }
157
- async fetchShell(id) {
158
- return this.fetchContentItem("shells", id);
159
- }
160
- async fetchRecipes() {
161
- return this.fetchContentList("recipes");
162
- }
163
- async fetchRecipe(id) {
164
- return this.fetchContentItem("recipes", id);
165
- }
166
- /**
167
- * Check if API is available.
168
- */
169
- async checkApiAvailability() {
170
- if (this.offline) return false;
171
- return this.apiClient.checkHealth();
172
- }
173
- };
174
- async function syncRegistry(cacheDir, apiUrl = DEFAULT_API_URL) {
175
- const apiClient = new RegistryAPIClient({ baseUrl: apiUrl });
176
- const synced = [];
177
- const failed = [];
178
- const healthy = await apiClient.checkHealth();
179
- if (!healthy) {
180
- return { synced: [], failed: ["API unavailable"] };
181
- }
182
- for (const type of ALL_CONTENT_TYPES) {
183
- try {
184
- const result = await apiClient.listContent(type, { namespace: "@official" });
185
- saveToCache(cacheDir, type, null, result, "@official");
186
- for (const item of result.items) {
187
- const id = item.id || item.slug;
188
- if (id) {
189
- saveToCache(cacheDir, type, id, item, "@official");
190
- }
191
- }
192
- synced.push(type);
193
- } catch {
194
- failed.push(type);
195
- }
196
- }
197
- return { synced, failed };
198
- }
199
-
200
- export {
201
- RegistryClient,
202
- syncRegistry
203
- };
@@ -1,66 +0,0 @@
1
- import {
2
- RegistryClient
3
- } from "./chunk-CT5XHG6I.js";
4
-
5
- // src/commands/upgrade.ts
6
- import { readFileSync, existsSync } from "fs";
7
- import { join } from "path";
8
- var GREEN = "\x1B[32m";
9
- var YELLOW = "\x1B[33m";
10
- var RESET = "\x1B[0m";
11
- var DIM = "\x1B[2m";
12
- async function cmdUpgrade(projectRoot = process.cwd()) {
13
- const essencePath = join(projectRoot, "decantr.essence.json");
14
- if (!existsSync(essencePath)) {
15
- console.error("No decantr.essence.json found. Run `decantr init` first.");
16
- process.exitCode = 1;
17
- return;
18
- }
19
- const essence = JSON.parse(readFileSync(essencePath, "utf-8"));
20
- const client = new RegistryClient({
21
- cacheDir: join(projectRoot, ".decantr", "cache")
22
- });
23
- console.log("Checking for updates...\n");
24
- const upgrades = [];
25
- if (essence.theme?.style) {
26
- const theme = await client.fetchTheme(essence.theme.style);
27
- if (theme && theme.data.version) {
28
- const current = essence.theme.version || "0.0.0";
29
- if (theme.data.version !== current) {
30
- upgrades.push({
31
- type: "theme",
32
- id: essence.theme.style,
33
- currentVersion: current,
34
- latestVersion: theme.data.version
35
- });
36
- }
37
- }
38
- }
39
- if (essence.blueprint) {
40
- const blueprint = await client.fetchBlueprint(essence.blueprint);
41
- if (blueprint && blueprint.data.version) {
42
- const current = essence.blueprintVersion || "0.0.0";
43
- if (blueprint.data.version !== current) {
44
- upgrades.push({
45
- type: "blueprint",
46
- id: essence.blueprint,
47
- currentVersion: current,
48
- latestVersion: blueprint.data.version
49
- });
50
- }
51
- }
52
- }
53
- if (upgrades.length === 0) {
54
- console.log(`${GREEN}Everything is up to date.${RESET}`);
55
- return;
56
- }
57
- console.log("Available upgrades:\n");
58
- for (const u of upgrades) {
59
- console.log(` ${u.type}/${u.id}: ${DIM}${u.currentVersion}${RESET} -> ${GREEN}${u.latestVersion}${RESET}`);
60
- }
61
- console.log(`
62
- ${YELLOW}Run with --apply to apply upgrades.${RESET}`);
63
- }
64
- export {
65
- cmdUpgrade
66
- };