@decantr/cli 2.8.0 → 2.9.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.
@@ -1,11 +1,87 @@
1
1
  import {
2
2
  createProjectHealthReport
3
- } from "./chunk-PAF4PBD3.js";
3
+ } from "./chunk-TMOCTDYY.js";
4
4
 
5
5
  // src/commands/workspace.ts
6
6
  import { execFileSync } from "child_process";
7
- import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "fs";
8
- import { dirname, join, relative, resolve } from "path";
7
+ import { existsSync as existsSync2, mkdirSync, readdirSync as readdirSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
8
+ import { dirname as dirname2, join as join2, relative, resolve as resolve2 } from "path";
9
+
10
+ // src/workspace.ts
11
+ import { existsSync, readdirSync, readFileSync } from "fs";
12
+ import { dirname, join, resolve } from "path";
13
+ function readPackageJson(dir) {
14
+ const path = join(dir, "package.json");
15
+ if (!existsSync(path)) return null;
16
+ try {
17
+ return JSON.parse(readFileSync(path, "utf-8"));
18
+ } catch {
19
+ return null;
20
+ }
21
+ }
22
+ function hasWorkspaceMarker(dir) {
23
+ if (existsSync(join(dir, "pnpm-workspace.yaml")) || existsSync(join(dir, "turbo.json")) || existsSync(join(dir, "nx.json"))) {
24
+ return true;
25
+ }
26
+ const pkg = readPackageJson(dir);
27
+ return Boolean(pkg?.workspaces);
28
+ }
29
+ function findWorkspaceRoot(startDir) {
30
+ let current = resolve(startDir);
31
+ while (true) {
32
+ if (hasWorkspaceMarker(current)) return current;
33
+ const parent = dirname(current);
34
+ if (parent === current) return null;
35
+ current = parent;
36
+ }
37
+ }
38
+ function looksLikeApp(dir, options = {}) {
39
+ const allowSourceDirs = options.allowSourceDirs ?? true;
40
+ if (existsSync(join(dir, "next.config.js")) || existsSync(join(dir, "next.config.ts")) || existsSync(join(dir, "next.config.mjs")) || existsSync(join(dir, "vite.config.ts")) || existsSync(join(dir, "vite.config.js")) || existsSync(join(dir, "angular.json")) || existsSync(join(dir, "svelte.config.js")) || existsSync(join(dir, "svelte.config.ts")) || existsSync(join(dir, "astro.config.mjs")) || allowSourceDirs && (existsSync(join(dir, "src")) || existsSync(join(dir, "app")) || existsSync(join(dir, "pages")))) {
41
+ return true;
42
+ }
43
+ const pkg = readPackageJson(dir);
44
+ const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };
45
+ return Boolean(
46
+ deps.react || deps.next || deps.vue || deps.svelte || deps["@angular/core"] || deps.astro || deps.nuxt
47
+ );
48
+ }
49
+ function listWorkspaceApps(workspaceRoot) {
50
+ const candidates = [];
51
+ for (const base of ["apps", "packages"]) {
52
+ const baseDir = join(workspaceRoot, base);
53
+ if (!existsSync(baseDir)) continue;
54
+ for (const entry of readdirSync(baseDir, { withFileTypes: true })) {
55
+ if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
56
+ const candidate = join(baseDir, entry.name);
57
+ if (looksLikeApp(candidate, { allowSourceDirs: base === "apps" })) {
58
+ candidates.push(`${base}/${entry.name}`);
59
+ }
60
+ }
61
+ }
62
+ return candidates.sort();
63
+ }
64
+ function listWorkspaceAppCandidates(workspaceRoot) {
65
+ return listWorkspaceApps(resolve(workspaceRoot));
66
+ }
67
+ function resolveWorkspaceInfo(cwd, projectArg) {
68
+ const absoluteCwd = resolve(cwd);
69
+ const workspaceRoot = findWorkspaceRoot(absoluteCwd) ?? absoluteCwd;
70
+ const appRoot = projectArg ? resolve(absoluteCwd, projectArg) : absoluteCwd;
71
+ const appCandidates = listWorkspaceApps(workspaceRoot);
72
+ const projectScope = workspaceRoot !== appRoot || appCandidates.length > 0 ? "workspace-app" : "single-app";
73
+ const requiresProjectSelection = !projectArg && workspaceRoot === absoluteCwd && appCandidates.length > 0;
74
+ return {
75
+ cwd: absoluteCwd,
76
+ workspaceRoot,
77
+ appRoot,
78
+ projectScope,
79
+ appCandidates,
80
+ requiresProjectSelection
81
+ };
82
+ }
83
+
84
+ // src/commands/workspace.ts
9
85
  var BOLD = "\x1B[1m";
10
86
  var DIM = "\x1B[2m";
11
87
  var GREEN = "\x1B[32m";
@@ -24,12 +100,12 @@ var DEFAULT_IGNORES = /* @__PURE__ */ new Set([
24
100
  "playwright-report"
25
101
  ]);
26
102
  function workspaceConfigPath(root) {
27
- return join(root, ".decantr", "workspace.json");
103
+ return join2(root, ".decantr", "workspace.json");
28
104
  }
29
105
  function readWorkspaceConfig(root) {
30
106
  const path = workspaceConfigPath(root);
31
- if (!existsSync(path)) return null;
32
- return JSON.parse(readFileSync(path, "utf-8"));
107
+ if (!existsSync2(path)) return null;
108
+ return JSON.parse(readFileSync2(path, "utf-8"));
33
109
  }
34
110
  function normalizeProjectPath(raw) {
35
111
  const normalized = raw.replace(/^\.\/+/, "").replace(/\/+$/, "");
@@ -48,21 +124,21 @@ function discoverProjectPaths(root, config) {
48
124
  if (depth > 6) return;
49
125
  const rel = relative(root, dir).replace(/\\/g, "/");
50
126
  if (rel && [...ignored].some((entry) => rel === entry || rel.startsWith(`${entry}/`))) return;
51
- if (existsSync(join(dir, "decantr.essence.json"))) {
127
+ if (existsSync2(join2(dir, "decantr.essence.json"))) {
52
128
  results.add(rel || ".");
53
129
  return;
54
130
  }
55
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
131
+ for (const entry of readdirSync2(dir, { withFileTypes: true })) {
56
132
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
57
133
  if (ignored.has(entry.name)) continue;
58
- walk(join(dir, entry.name), depth + 1);
134
+ walk(join2(dir, entry.name), depth + 1);
59
135
  }
60
136
  }
61
137
  walk(root, 0);
62
138
  return [...results].sort();
63
139
  }
64
140
  function listWorkspaceProjects(root = process.cwd()) {
65
- const workspaceRoot = resolve(root);
141
+ const workspaceRoot = resolve2(root);
66
142
  const config = readWorkspaceConfig(workspaceRoot);
67
143
  const byPath = /* @__PURE__ */ new Map();
68
144
  for (const project of config?.projects ?? []) {
@@ -70,7 +146,7 @@ function listWorkspaceProjects(root = process.cwd()) {
70
146
  byPath.set(path, {
71
147
  id: project.id ?? projectIdFromPath(path),
72
148
  path,
73
- absolutePath: resolve(workspaceRoot, path),
149
+ absolutePath: resolve2(workspaceRoot, path),
74
150
  owner: project.owner ?? null,
75
151
  tags: project.tags ?? [],
76
152
  criticality: project.criticality ?? "normal",
@@ -83,7 +159,7 @@ function listWorkspaceProjects(root = process.cwd()) {
83
159
  byPath.set(path, {
84
160
  id: projectIdFromPath(path),
85
161
  path,
86
- absolutePath: resolve(workspaceRoot, path),
162
+ absolutePath: resolve2(workspaceRoot, path),
87
163
  owner: null,
88
164
  tags: [],
89
165
  criticality: "normal",
@@ -93,6 +169,14 @@ function listWorkspaceProjects(root = process.cwd()) {
93
169
  }
94
170
  return [...byPath.values()].sort((a, b) => a.path.localeCompare(b.path));
95
171
  }
172
+ function listWorkspaceCandidates(root = process.cwd(), projects = listWorkspaceProjects(root)) {
173
+ const attached = new Set(projects.map((project) => project.path));
174
+ return listWorkspaceAppCandidates(root).map((path) => ({
175
+ path,
176
+ attached: attached.has(path),
177
+ suggestedAdoptCommand: `decantr adopt --project ${path} --yes`
178
+ }));
179
+ }
96
180
  function changedPaths(root, since) {
97
181
  try {
98
182
  const output = execFileSync("git", ["diff", "--name-only", since, "--"], {
@@ -100,7 +184,9 @@ function changedPaths(root, since) {
100
184
  encoding: "utf-8",
101
185
  stdio: ["ignore", "pipe", "ignore"]
102
186
  });
103
- return new Set(output.split("\n").map((line) => line.trim()).filter(Boolean));
187
+ return new Set(
188
+ output.split("\n").map((line) => line.trim()).filter(Boolean)
189
+ );
104
190
  } catch {
105
191
  return /* @__PURE__ */ new Set();
106
192
  }
@@ -116,7 +202,10 @@ function projectChanged(project, changed) {
116
202
  async function withTimeout(promise, timeoutMs, label) {
117
203
  let timeout;
118
204
  const timer = new Promise((_, reject) => {
119
- timeout = setTimeout(() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs);
205
+ timeout = setTimeout(
206
+ () => reject(new Error(`${label} timed out after ${timeoutMs}ms`)),
207
+ timeoutMs
208
+ );
120
209
  });
121
210
  try {
122
211
  return await Promise.race([promise, timer]);
@@ -137,7 +226,7 @@ async function mapLimited(items, concurrency, fn) {
137
226
  return results;
138
227
  }
139
228
  async function createWorkspaceHealthReport(root = process.cwd(), options = {}) {
140
- const workspaceRoot = resolve(root);
229
+ const workspaceRoot = resolve2(root);
141
230
  const config = readWorkspaceConfig(workspaceRoot);
142
231
  const since = options.since ?? "origin/main";
143
232
  const changed = options.changedOnly ? changedPaths(workspaceRoot, since) : /* @__PURE__ */ new Set();
@@ -265,9 +354,11 @@ function parseWorkspaceArgs(args) {
265
354
  else if (arg.startsWith("--since=")) options.since = arg.split("=")[1];
266
355
  else if (arg === "--output" && args[index + 1]) options.output = args[++index];
267
356
  else if (arg.startsWith("--output=")) options.output = arg.split("=")[1];
268
- else if (arg === "--fail-on" && args[index + 1]) options.failOn = parseHealthFailOn(args[++index]);
357
+ else if (arg === "--fail-on" && args[index + 1])
358
+ options.failOn = parseHealthFailOn(args[++index]);
269
359
  else if (arg.startsWith("--fail-on=")) options.failOn = parseHealthFailOn(arg.split("=")[1]);
270
- else if (arg === "--concurrency" && args[index + 1]) options.concurrency = Number(args[++index]);
360
+ else if (arg === "--concurrency" && args[index + 1])
361
+ options.concurrency = Number(args[++index]);
271
362
  else if (arg.startsWith("--concurrency=")) options.concurrency = Number(arg.split("=")[1]);
272
363
  else if (arg === "--timeout-ms" && args[index + 1]) options.timeoutMs = Number(args[++index]);
273
364
  else if (arg.startsWith("--timeout-ms=")) options.timeoutMs = Number(arg.split("=")[1]);
@@ -278,15 +369,36 @@ async function cmdWorkspace(workspaceRoot = process.cwd(), args = ["workspace"])
278
369
  const options = parseWorkspaceArgs(args);
279
370
  if (options.subcommand === "list") {
280
371
  const projects = listWorkspaceProjects(workspaceRoot);
281
- const payload2 = `${JSON.stringify({ projects }, null, 2)}
372
+ const candidates = listWorkspaceCandidates(workspaceRoot, projects);
373
+ const unattachedCandidates = candidates.filter((candidate) => !candidate.attached);
374
+ const payload2 = `${JSON.stringify({ projects, candidates }, null, 2)}
282
375
  `;
283
376
  if (options.json) {
284
377
  process.stdout.write(payload2);
285
378
  return;
286
379
  }
287
380
  console.log(`${BOLD}Decantr workspace projects${RESET}`);
288
- for (const project of projects) {
289
- console.log(`${project.path} ${DIM}${project.source}${RESET}`);
381
+ console.log("");
382
+ console.log("Attached Decantr projects:");
383
+ if (projects.length === 0) {
384
+ console.log(` ${DIM}(none yet)${RESET}`);
385
+ } else {
386
+ for (const project of projects) {
387
+ console.log(` ${project.path} ${DIM}${project.source}${RESET}`);
388
+ }
389
+ }
390
+ if (candidates.length > 0) {
391
+ console.log("");
392
+ console.log("App candidates:");
393
+ for (const candidate of candidates) {
394
+ const status = candidate.attached ? `${GREEN}attached${RESET}` : `${YELLOW}unattached${RESET}`;
395
+ console.log(` ${candidate.path} ${DIM}${status}${RESET}`);
396
+ }
397
+ }
398
+ if (unattachedCandidates.length > 0) {
399
+ console.log("");
400
+ console.log("Start by attaching one app:");
401
+ console.log(` ${unattachedCandidates[0].suggestedAdoptCommand}`);
290
402
  }
291
403
  return;
292
404
  }
@@ -294,9 +406,10 @@ async function cmdWorkspace(workspaceRoot = process.cwd(), args = ["workspace"])
294
406
  const payload = options.json ? `${JSON.stringify(report, null, 2)}
295
407
  ` : options.markdown ? formatWorkspaceHealthMarkdown(report) : formatWorkspaceHealthText(report);
296
408
  if (options.output) {
297
- mkdirSync(dirname(resolve(workspaceRoot, options.output)), { recursive: true });
298
- writeFileSync(resolve(workspaceRoot, options.output), payload, "utf-8");
299
- if (!options.ci) console.log(`${GREEN}Wrote Decantr workspace health:${RESET} ${options.output}`);
409
+ mkdirSync(dirname2(resolve2(workspaceRoot, options.output)), { recursive: true });
410
+ writeFileSync(resolve2(workspaceRoot, options.output), payload, "utf-8");
411
+ if (!options.ci)
412
+ console.log(`${GREEN}Wrote Decantr workspace health:${RESET} ${options.output}`);
300
413
  } else {
301
414
  process.stdout.write(payload);
302
415
  }
@@ -306,7 +419,9 @@ async function cmdWorkspace(workspaceRoot = process.cwd(), args = ["workspace"])
306
419
  }
307
420
 
308
421
  export {
422
+ resolveWorkspaceInfo,
309
423
  listWorkspaceProjects,
424
+ listWorkspaceCandidates,
310
425
  createWorkspaceHealthReport,
311
426
  formatWorkspaceHealthText,
312
427
  formatWorkspaceHealthMarkdown,
@@ -1,11 +1,9 @@
1
1
  import {
2
- collectCheckIssues
3
- } from "./chunk-3TH5PLFO.js";
4
- import {
2
+ collectCheckIssues,
5
3
  sendProjectHealthCiFailedTelemetry,
6
4
  sendProjectHealthPromptTelemetry,
7
5
  sendProjectHealthReportTelemetry
8
- } from "./chunk-KT2ROK2D.js";
6
+ } from "./chunk-34TZXWIF.js";
9
7
 
10
8
  // src/commands/health.ts
11
9
  import { execFileSync } from "child_process";
@@ -227,6 +225,26 @@ function sourceFromCheckIssue(issue) {
227
225
  if (issue.rule.includes("interaction")) return "interaction";
228
226
  return "check";
229
227
  }
228
+ function normalizeHealthCategory(category, source) {
229
+ const lower = category.toLowerCase();
230
+ if (source === "pack" || lower.includes("execution pack") || lower.includes("review contract") || lower.includes("context")) {
231
+ return "Generated Artifact";
232
+ }
233
+ if (source === "brownfield") return "Brownfield Contract";
234
+ if (source === "design-token" || lower.includes("design-token")) return "Design Token";
235
+ if (lower.includes("accessibility")) return "Accessibility";
236
+ if (source === "runtime") return "Runtime";
237
+ if (source === "browser") return "Visual Evidence";
238
+ if (source === "interaction") return "Interaction";
239
+ if (source === "assertion") return `Contract ${category}`;
240
+ return category;
241
+ }
242
+ function contractAssertionApplies(assertion, metadata) {
243
+ if (assertion.rule === "tokens-file-present" && metadata.adoptionMode === "contract-only") {
244
+ return false;
245
+ }
246
+ return true;
247
+ }
230
248
  function slugify(value) {
231
249
  return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
232
250
  }
@@ -298,13 +316,14 @@ function createHealthFinding(input) {
298
316
  const idBase = input.baseId || input.rule || `${input.category}-${input.message}`;
299
317
  const id = `${input.source}-${slugify(idBase)}`;
300
318
  const commands = commandsForFinding(input.source);
319
+ const category = normalizeHealthCategory(input.category, input.source);
301
320
  const remediation = {
302
- summary: input.suggestedFix || `Resolve ${input.category.toLowerCase()} finding.`,
321
+ summary: input.suggestedFix || `Resolve ${category.toLowerCase()} finding.`,
303
322
  commands,
304
323
  prompt: buildRemediationPrompt({
305
324
  id,
306
325
  source: input.source,
307
- category: input.category,
326
+ category,
308
327
  severity: input.severity,
309
328
  message: input.message,
310
329
  evidence: input.evidence ?? [],
@@ -315,7 +334,7 @@ function createHealthFinding(input) {
315
334
  return {
316
335
  id,
317
336
  source: input.source,
318
- category: input.category,
337
+ category,
319
338
  severity: input.severity,
320
339
  message: input.message,
321
340
  evidence: input.evidence ?? [],
@@ -787,6 +806,7 @@ async function createProjectHealthReport(projectRoot = process.cwd(), options =
787
806
  if (!isDuplicateFinding(seen, healthFinding)) findings.push(healthFinding);
788
807
  }
789
808
  for (const contractAssertion of createContractAssertions(projectRoot, audit)) {
809
+ if (!contractAssertionApplies(contractAssertion, metadata)) continue;
790
810
  if (contractAssertion.status !== "failed") continue;
791
811
  const healthFinding = createHealthFinding({
792
812
  source: "assertion",
@@ -893,7 +913,7 @@ async function createProjectHealthReport(projectRoot = process.cwd(), options =
893
913
  generatedAt: typeof manifest?.generatedAt === "string" ? manifest.generatedAt : null
894
914
  },
895
915
  ci: {
896
- recommendedCommand: "decantr health --ci --fail-on error",
916
+ recommendedCommand: "decantr ci --fail-on error",
897
917
  failOn: "error"
898
918
  },
899
919
  findings
@@ -172,7 +172,9 @@ function statusFromCounts(counts) {
172
172
  function scoreFromCounts(counts) {
173
173
  const warningPenalty = Math.min(counts.warnCount * 2, 75);
174
174
  const infoPenalty = Math.min(counts.infoCount * 0.5, 10);
175
- return Math.round(Math.max(0, Math.min(100, 100 - counts.errorCount * 15 - warningPenalty - infoPenalty)));
175
+ return Math.round(
176
+ Math.max(0, Math.min(100, 100 - counts.errorCount * 15 - warningPenalty - infoPenalty))
177
+ );
176
178
  }
177
179
  function percentage(count, total) {
178
180
  if (total === 0) return 1;
@@ -728,7 +730,9 @@ async function createContentHealthReport(contentRoot = process.cwd(), options =
728
730
  category: "Content Root",
729
731
  severity: "error",
730
732
  message: "No Decantr registry content was found in this directory.",
731
- evidence: ["Expected one or more of patterns/, themes/, blueprints/, archetypes/, shells/."],
733
+ evidence: [
734
+ "Expected one or more of patterns/, themes/, blueprints/, archetypes/, shells/."
735
+ ],
732
736
  rule: "content-root-empty",
733
737
  suggestedFix: "Run this command from a decantr-content style repository.",
734
738
  baseId: "content-root-empty"
@@ -828,11 +832,15 @@ async function createContentHealthReport(contentRoot = process.cwd(), options =
828
832
  patterns.length
829
833
  ),
830
834
  patternInteractionCoverage: percentage(
831
- patterns.filter((item) => Array.isArray(item.data.interactions) && item.data.interactions.length > 0).length,
835
+ patterns.filter(
836
+ (item) => Array.isArray(item.data.interactions) && item.data.interactions.length > 0
837
+ ).length,
832
838
  patterns.length
833
839
  ),
834
840
  themeDecoratorCoverage: percentage(
835
- themes.filter((item) => isRecord(item.data.decorators) && Object.keys(item.data.decorators).length > 0).length,
841
+ themes.filter(
842
+ (item) => isRecord(item.data.decorators) && Object.keys(item.data.decorators).length > 0
843
+ ).length,
836
844
  themes.length
837
845
  ),
838
846
  blueprintPersonalityCoverage: percentage(
@@ -842,7 +850,10 @@ async function createContentHealthReport(contentRoot = process.cwd(), options =
842
850
  }).length,
843
851
  blueprints.length
844
852
  ),
845
- blueprintVoiceCoverage: percentage(blueprints.filter((item) => isRecord(item.data.voice)).length, blueprints.length),
853
+ blueprintVoiceCoverage: percentage(
854
+ blueprints.filter((item) => isRecord(item.data.voice)).length,
855
+ blueprints.length
856
+ ),
846
857
  archetypePageBriefCoverage: percentage(
847
858
  archetypes.filter((item) => isRecord(item.data.page_briefs)).length,
848
859
  archetypes.length
@@ -896,10 +907,12 @@ function formatContentHealthText(report) {
896
907
  );
897
908
  if (finding.file) lines.push(` ${DIM}${finding.file}${RESET}`);
898
909
  if (finding.suggestedFix) lines.push(` ${DIM}Fix: ${finding.suggestedFix}${RESET}`);
899
- lines.push(` ${DIM}Prompt: decantr content-health --prompt ${finding.id}${RESET}`);
910
+ lines.push(` ${DIM}Prompt: decantr content check --prompt ${finding.id}${RESET}`);
900
911
  }
901
912
  if (report.findings.length > 40) {
902
- lines.push(` ${DIM}Showing first 40 of ${report.findings.length} findings. Use --json for the full report.${RESET}`);
913
+ lines.push(
914
+ ` ${DIM}Showing first 40 of ${report.findings.length} findings. Use --json for the full report.${RESET}`
915
+ );
903
916
  }
904
917
  }
905
918
  lines.push("");
@@ -931,10 +944,14 @@ function formatContentHealthMarkdown(report) {
931
944
  lines.push("");
932
945
  lines.push("## Quality Coverage");
933
946
  lines.push("");
934
- lines.push(`- Pattern visual guidance: ${percentLabel(report.quality.patternVisualBriefCoverage)}`);
947
+ lines.push(
948
+ `- Pattern visual guidance: ${percentLabel(report.quality.patternVisualBriefCoverage)}`
949
+ );
935
950
  lines.push(`- Pattern interactions: ${percentLabel(report.quality.patternInteractionCoverage)}`);
936
951
  lines.push(`- Theme decorators: ${percentLabel(report.quality.themeDecoratorCoverage)}`);
937
- lines.push(`- Blueprint personality: ${percentLabel(report.quality.blueprintPersonalityCoverage)}`);
952
+ lines.push(
953
+ `- Blueprint personality: ${percentLabel(report.quality.blueprintPersonalityCoverage)}`
954
+ );
938
955
  lines.push(`- Blueprint voice: ${percentLabel(report.quality.blueprintVoiceCoverage)}`);
939
956
  lines.push(`- Archetype page briefs: ${percentLabel(report.quality.archetypePageBriefCoverage)}`);
940
957
  lines.push("");
@@ -958,7 +975,7 @@ function formatContentHealthMarkdown(report) {
958
975
  lines.push("- Evidence:");
959
976
  for (const evidence of finding.evidence) lines.push(` - ${evidence}`);
960
977
  }
961
- lines.push(`- Prompt: \`decantr content-health --prompt ${finding.id}\``);
978
+ lines.push(`- Prompt: \`decantr content check --prompt ${finding.id}\``);
962
979
  lines.push("");
963
980
  }
964
981
  }
@@ -1,8 +1,7 @@
1
1
  import {
2
2
  cmdHeal,
3
3
  collectCheckIssues
4
- } from "./chunk-3TH5PLFO.js";
5
- import "./chunk-KT2ROK2D.js";
4
+ } from "./chunk-34TZXWIF.js";
6
5
  export {
7
6
  cmdHeal,
8
7
  collectCheckIssues
@@ -10,9 +10,8 @@ import {
10
10
  renderProjectHealthCiWorkflow,
11
11
  shouldFailHealth,
12
12
  writeProjectHealthCiWorkflow
13
- } from "./chunk-PAF4PBD3.js";
14
- import "./chunk-3TH5PLFO.js";
15
- import "./chunk-KT2ROK2D.js";
13
+ } from "./chunk-TMOCTDYY.js";
14
+ import "./chunk-34TZXWIF.js";
16
15
  export {
17
16
  cmdHealth,
18
17
  collectDesignTokenEvidence,
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
- import "./chunk-QTPNV5WU.js";
1
+ import "./chunk-N7A3WUZ2.js";
2
2
  import "./chunk-V3XAQWKD.js";
3
- import "./chunk-KT2ROK2D.js";
3
+ import "./chunk-T5INVSOP.js";
4
+ import "./chunk-TMOCTDYY.js";
5
+ import "./chunk-34TZXWIF.js";
@@ -1,14 +1,13 @@
1
1
  import {
2
2
  createWorkspaceHealthReport
3
- } from "./chunk-ICSLIYSX.js";
3
+ } from "./chunk-T5INVSOP.js";
4
4
  import {
5
5
  createProjectHealthReport
6
- } from "./chunk-PAF4PBD3.js";
7
- import "./chunk-3TH5PLFO.js";
6
+ } from "./chunk-TMOCTDYY.js";
8
7
  import {
9
8
  sendStudioHealthRefreshedTelemetry,
10
9
  sendStudioStartedTelemetry
11
- } from "./chunk-KT2ROK2D.js";
10
+ } from "./chunk-34TZXWIF.js";
12
11
 
13
12
  // src/commands/studio.ts
14
13
  import { readFileSync } from "fs";
@@ -3,18 +3,19 @@ import {
3
3
  createWorkspaceHealthReport,
4
4
  formatWorkspaceHealthMarkdown,
5
5
  formatWorkspaceHealthText,
6
+ listWorkspaceCandidates,
6
7
  listWorkspaceProjects,
7
8
  parseWorkspaceArgs,
8
9
  shouldFailWorkspaceHealth
9
- } from "./chunk-ICSLIYSX.js";
10
- import "./chunk-PAF4PBD3.js";
11
- import "./chunk-3TH5PLFO.js";
12
- import "./chunk-KT2ROK2D.js";
10
+ } from "./chunk-T5INVSOP.js";
11
+ import "./chunk-TMOCTDYY.js";
12
+ import "./chunk-34TZXWIF.js";
13
13
  export {
14
14
  cmdWorkspace,
15
15
  createWorkspaceHealthReport,
16
16
  formatWorkspaceHealthMarkdown,
17
17
  formatWorkspaceHealthText,
18
+ listWorkspaceCandidates,
18
19
  listWorkspaceProjects,
19
20
  parseWorkspaceArgs,
20
21
  shouldFailWorkspaceHealth
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decantr/cli",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "description": "Decantr CLI - scaffold, audit, inspect Project Health, and maintain Decantr projects from the terminal",
5
5
  "keywords": [
6
6
  "decantr",
@@ -50,9 +50,9 @@
50
50
  "ajv": "^8.20.0",
51
51
  "@decantr/core": "2.1.0",
52
52
  "@decantr/registry": "2.2.0",
53
- "@decantr/verifier": "2.2.0",
54
53
  "@decantr/essence-spec": "2.0.1",
55
- "@decantr/telemetry": "2.2.1"
54
+ "@decantr/telemetry": "2.2.1",
55
+ "@decantr/verifier": "2.3.0"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsup",