@decantr/cli 3.5.5 → 3.6.1

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 CHANGED
@@ -23,7 +23,7 @@ Use `decantr scan` when you want a zero-commit Brownfield preview. It reads loca
23
23
  Use `decantr new` for a greenfield workspace in a fresh directory. With a starter-kit blueprint or archetype it uses the runnable adapter and Decantr CSS; without certified vocabulary content it creates a contract-only workspace unless you explicitly pass `--adoption=decantr-css`.
24
24
  Use `decantr adopt` when you already have an app and want Decantr governance without adopting a blueprint. Brownfield attach is proposal-driven: Decantr inventories the app, writes an observed essence proposal, hydrates hosted execution packs when online, and only applies the contract when you explicitly accept or merge it.
25
25
  Use `decantr studio` after adoption when you want a local Control Room for routes, findings, evidence, authority, and next actions. Use `decantr doctor` when the next step is unclear, `decantr task <route> "<intent>"` before asking an LLM to modify a route, `decantr verify` after the edit, `decantr resolve` when source and contract disagree, and `decantr ci` in required automation. If runtime source and Decantr context disagree, report the drift instead of guessing; in Brownfield the existing source is observed truth, accepted local law/style bridge is project authority where present, Essence V4 is the structural contract, and hosted packs stay advisory until mapped into local law. Use `decantr graph` when you want the Decantr 3 typed Contract graph, typed graph diff summary, manifest, content-addressed snapshot history, and cache-friendly contract capsule written under `.decantr/graph`; the capsule includes a bounded SourceArtifact path index so agents can discover valid file-impact handles without reading the full snapshot, and `--capsule-source-limit <count>` can tune that index for large repos. Add `--route /feed --task "improve loading" --json` when you want the exact task-ranked route-scoped subgraph an agent should inspect before editing, `--node cmp:button --impact --json` when you need the graph-shaped blast radius for a component, token, rule, finding, or source artifact, or `--file src/app/page.tsx --impact --json` when the agent knows the source file it is about to change. Route and impact ranking use deterministic weighted traversal plus local personalized PageRank and task boosts. Use `--snapshot-id <id>` to inspect a replayable history snapshot and `--compare-to <id> --include-diff-ops --json` to compare the selected/current graph against a prior snapshot. Use `decantr codify --from-audit --style-bridge` when you want project-owned UI patterns, optional `behavior_obligations`, local rules, and token/class bridge mappings such as button/card/shell/theme standards to appear in future task context and verification. Once accepted, that local law is the first Hybrid lane: the app still owns source and styling, but Decantr treats accepted local patterns, behavior obligations, rules, and style bridge mappings as project authority.
26
- In monorepos, app-scoped commands accept `--project <app-path>`. `setup` shows attach guidance before adoption and the day-two loop after adoption. Hosted pack hydration also follows the essence path: `decantr registry compile-packs apps/web/decantr.essence.json --write-context` writes into `apps/web/.decantr/context`. In contract-only/offline Brownfield, deferred hosted packs are optional context unless a present manifest references missing files.
26
+ In monorepos, app-scoped commands accept `--project <app-path>`. `setup` shows attach guidance before adoption and the day-two loop after adoption. Candidate discovery ranks product UI apps ahead of docs, Storybook, API, MCP helper, workbench, and package surfaces; `decantr workspace list --json` includes rank, category, score, and reason metadata so automation can explain why `apps/web`, `apps/remix`, or `apps/dashboard` was suggested first. Hosted pack hydration also follows the essence path: `decantr registry compile-packs apps/web/decantr.essence.json --write-context` writes into `apps/web/.decantr/context`. In contract-only/offline Brownfield, deferred hosted packs are optional context unless a present manifest references missing files.
27
27
  Use `decantr init`, `decantr analyze`, `decantr check`, and `decantr health` as advanced primitives when you need direct control over one step.
28
28
 
29
29
  App-scoped primitives now share the same `--project` posture as the primary workflow commands. From a workspace root, `health`, `status`, `upgrade`, `add`, `remove`, `theme`, `export`, `suggest`, `magic`, `rules`, and `telemetry` target the selected app instead of the root. Task/read paths, local-law summaries, and refresh change summaries are printed as openable workspace paths. Nonexistent project paths fail immediately, and Brownfield adoption refuses component packages unless you intentionally pass `--force-package`.
@@ -103,12 +103,14 @@ Assistant rule integration is preview-first: `--assistant-bridge=preview` writes
103
103
  - previews existing apps with read-only Brownfield scan reports
104
104
  - guides users through human workflow commands: setup, adopt, doctor, task, verify, ci, and codify
105
105
  - supports explicit workflow lanes: greenfield blueprint, greenfield contract-only, brownfield adoption, Hybrid local law, Hybrid style bridge, Hybrid Decantr CSS, and hybrid composition
106
+ - ranks monorepo app candidates with explainable metadata so product UI apps come before docs, Storybook, API, helper packages, and workbench surfaces
106
107
  - generates execution-pack context files for AI coding assistants
107
108
  - generates typed Contract graph artifacts, replayable snapshot history, graph diffs, manifests, source-file impact context, style-bridge Token nodes, behavior-obligation LocalRule nodes, and `contract-capsule.json` for agent sessions
108
109
  - audits projects against Decantr contracts
109
110
  - produces local Project Health reports, Evidence Bundles, workspace health, and a localhost Studio dashboard for end-user drift triage
110
111
  - audits local vocabulary repositories with Content Health reports for schema, reference, and quality coverage
111
112
  - searches the registry and showcase benchmark corpus
113
+ - runs real-world corpus harnesses with timing percentiles, slow-command budgets, root-smoke/app-scoped classification, and stable failure categories
112
114
  - filters blueprints through public portfolio sets: `All`, `Featured`, `Certified`, and opt-in `Labs`
113
115
  - syncs paginated hosted vocabulary content into a full slug-keyed local cache for offline guards and context generation
114
116
  - validates, refreshes, and maintains `decantr.essence.json`
@@ -184,7 +186,7 @@ decantr showcase verification --json
184
186
 
185
187
  `decantr ci` is the blessed non-mutating automation gate. It runs the Project Health surface with adoption-mode-aware local law checks and emits a schema-backed CI report. `decantr ci init` writes root GitHub workflows or portable generic snippets using the detected package manager and pinned local CLI command instead of `@latest`; if the root manifest has not pinned Decantr yet, it prints the exact install command first.
186
188
 
187
- `decantr health` remains the advanced project observability primitive. It composes the existing verifier audit, guard checks, brownfield route drift checks, runtime evidence, component reuse drift, accepted style bridge drift, accepted behavior-obligation checks, typed Contract graph freshness, and execution-pack files into a v2 `ProjectHealthReport` with status, score, route summary, pack summary, findings, stable diagnostic codes, typed repair IDs, evidence tier, authority resolution, loop readiness, and AI-ready remediation prompts. The graph freshness slice emits `GRAPH001` / `regenerate-typed-graph` when an attached app has missing, stale, or non-derivable `.decantr/graph` artifacts. The component reuse slice emits `COMP001` / `import-existing-component` when production source locally redeclares a common primitive that already exists as an exported reusable component, and `COMP010` / `replace-raw-control-with-local-component` when production JSX renders raw controls such as `<button>` while the project already owns a reusable primitive. The behavior-obligation slice emits `A11Y010`, `A11Y011`, `INT010`, `INT011`, `INT012`, `INT013`, and `COMP020` for high-confidence dialog/form regressions such as missing accessible names, missing label associations, missing visible destructive consequence copy, missing cancel affordances, missing submitting guards, implicit form button types, or bypassed project-owned interaction primitives. The style bridge slice emits `TOKEN010` / `replace-arbitrary-style-with-bridge-token` when production JSX, common class helpers, hardcoded inline color styles, or hardcoded visual values in CSS/module stylesheets bypass `.decantr/style-bridge.json` after it has been accepted as project-owned style authority. The baseline slice emits `VISUAL010` / `review-visual-baseline-drift` when `--since-baseline` detects changed screenshot hashes. When `.decantr/graph/graph.snapshot.json` exists, each finding is anchored to the most specific graph node Decantr can resolve, and JSON, markdown, text output, repair prompts, and Evidence Bundles carry that anchor. `decantr graph` also writes content-addressed history snapshots under `.decantr/graph/snapshots/` so repeated graph runs can be replayed across an AI edit sequence. When `.decantr/analysis.json` exists, `decantr graph` links observed routes/pages to implementation source artifacts and links exported reusable component declarations to their source files. When browser evidence writes `.decantr/evidence/visual-manifest.json`, `decantr graph` ingests it as local route/page Evidence nodes without uploading screenshots. When `.decantr/evidence/latest.json` exists, `decantr graph` can also materialize saved findings, evidence strings, graph anchors, repair IDs, and referenced repair/read target files as typed graph nodes and edges. When `.decantr/health-baseline-diff.json` exists, baseline changed files become file-level temporal evidence in the graph.
189
+ `decantr health` remains the advanced project observability primitive. It composes the existing verifier audit, guard checks, brownfield route drift checks, runtime evidence, component reuse drift, accepted style bridge drift, accepted behavior-obligation checks, typed Contract graph freshness, and execution-pack files into a v2 `ProjectHealthReport` with status, score, route summary, pack summary, findings, stable diagnostic codes, typed repair IDs, evidence tier, authority resolution, loop readiness, and AI-ready remediation prompts. The graph freshness slice emits `GRAPH001` / `regenerate-typed-graph` when an attached app has missing, stale, or non-derivable `.decantr/graph` artifacts. The component reuse slice emits `COMP001` / `import-existing-component` when production source locally redeclares a common primitive that already exists as an exported reusable component, and `COMP010` / `replace-raw-control-with-local-component` when production JSX renders generic raw controls such as `<button>` or text-like `<input>` while the project already owns a reusable primitive. Specialized inputs such as file, hidden, checkbox, radio, color, range, and Dropzone `getInputProps()` controls are not treated as generic `Input` drift. The behavior-obligation slice emits `A11Y010`, `A11Y011`, `INT010`, `INT011`, `INT012`, `INT013`, and `COMP020` for high-confidence dialog/form regressions such as missing accessible names, missing label associations, missing visible destructive consequence copy, missing cancel affordances, missing submitting guards, implicit form button types, or bypassed project-owned interaction primitives. The style bridge slice emits `TOKEN010` / `replace-arbitrary-style-with-bridge-token` when production JSX, common class helpers, hardcoded inline color styles, or hardcoded visual values in CSS/module stylesheets bypass `.decantr/style-bridge.json` after it has been accepted as project-owned style authority. The baseline slice emits `VISUAL010` / `review-visual-baseline-drift` when `--since-baseline` detects changed screenshot hashes. When `.decantr/graph/graph.snapshot.json` exists, each finding is anchored to the most specific graph node Decantr can resolve, and JSON, markdown, text output, repair prompts, and Evidence Bundles carry that anchor. `decantr graph` also writes content-addressed history snapshots under `.decantr/graph/snapshots/` so repeated graph runs can be replayed across an AI edit sequence. When `.decantr/analysis.json` exists, `decantr graph` links observed routes/pages to implementation source artifacts and links exported reusable component declarations to their source files. When browser evidence writes `.decantr/evidence/visual-manifest.json`, `decantr graph` ingests it as local route/page Evidence nodes without uploading screenshots. When `.decantr/evidence/latest.json` exists, `decantr graph` can also materialize saved findings, evidence strings, graph anchors, repair IDs, and referenced repair/read target files as typed graph nodes and edges. When `.decantr/health-baseline-diff.json` exists, baseline changed files become file-level temporal evidence in the graph.
188
190
 
189
191
  ```bash
190
192
  decantr verify
package/dist/bin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-4O74E2PS.js";
2
+ import "./chunk-TGVBWTDK.js";
3
3
  import "./chunk-SIDKK73N.js";
4
- import "./chunk-FIWVRMZN.js";
5
- import "./chunk-U62GGKUO.js";
4
+ import "./chunk-56HUEUO3.js";
5
+ import "./chunk-WAGVDMJV.js";
6
6
  import "./chunk-24JR4ZNG.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createProjectHealthReport,
3
- listWorkspaceAppCandidates
4
- } from "./chunk-U62GGKUO.js";
3
+ listWorkspaceAppCandidateDetails
4
+ } from "./chunk-WAGVDMJV.js";
5
5
 
6
6
  // src/commands/workspace.ts
7
7
  import { execFileSync } from "child_process";
@@ -97,10 +97,14 @@ function listWorkspaceProjects(root = process.cwd()) {
97
97
  }
98
98
  function listWorkspaceCandidates(root = process.cwd(), projects = listWorkspaceProjects(root)) {
99
99
  const attached = new Set(projects.map((project) => project.path));
100
- return listWorkspaceAppCandidates(root).map((path) => ({
101
- path,
102
- attached: attached.has(path),
103
- suggestedAdoptCommand: `decantr adopt --project ${path} --yes`
100
+ return listWorkspaceAppCandidateDetails(root).map((candidate, index) => ({
101
+ path: candidate.path,
102
+ attached: attached.has(candidate.path),
103
+ suggestedAdoptCommand: `decantr adopt --project ${candidate.path} --yes`,
104
+ rank: index + 1,
105
+ score: candidate.score,
106
+ category: candidate.category,
107
+ reason: candidate.reason
104
108
  }));
105
109
  }
106
110
  function changedPaths(root, since) {
@@ -342,7 +346,9 @@ async function cmdWorkspace(workspaceRoot = process.cwd(), args = ["workspace"])
342
346
  console.log("App candidates:");
343
347
  for (const candidate of candidates) {
344
348
  const status = candidate.attached ? `${GREEN}attached${RESET}` : `${YELLOW}unattached${RESET}`;
345
- console.log(` ${candidate.path} ${DIM}${status}${RESET}`);
349
+ console.log(
350
+ ` #${candidate.rank} ${candidate.path} ${DIM}${status} \xB7 ${candidate.category} \xB7 score ${candidate.score}${RESET}`
351
+ );
346
352
  }
347
353
  }
348
354
  if (unattachedCandidates.length > 0) {
@@ -22,7 +22,7 @@ import {
22
22
  listWorkspaceCandidates,
23
23
  listWorkspaceProjects,
24
24
  shouldFailWorkspaceHealth
25
- } from "./chunk-FIWVRMZN.js";
25
+ } from "./chunk-56HUEUO3.js";
26
26
  import {
27
27
  acceptBrownfieldLocalLaw,
28
28
  acceptStyleBridge,
@@ -52,7 +52,7 @@ import {
52
52
  writeBrownfieldCodifyProposal,
53
53
  writeHostedPatternMappingProposal,
54
54
  writeStyleBridgeProposal
55
- } from "./chunk-U62GGKUO.js";
55
+ } from "./chunk-WAGVDMJV.js";
56
56
  import {
57
57
  buildGuardRegistryContext,
58
58
  createDoctrineMap,
@@ -11093,7 +11093,7 @@ async function cmdAdoptWorkflow(args) {
11093
11093
  await cmdGraph(projectRoot, { displayRoot: process.cwd() });
11094
11094
  if (process.exitCode && process.exitCode !== 0) return;
11095
11095
  if (runVerify) {
11096
- const { cmdHealth } = await import("./health-RRIM7YAV.js");
11096
+ const { cmdHealth } = await import("./health-KUPBUU3B.js");
11097
11097
  await cmdHealth(projectRoot, {
11098
11098
  browser: runBrowser,
11099
11099
  browserBaseUrl: baseUrl,
@@ -11167,7 +11167,7 @@ async function cmdVerifyWorkflow(args) {
11167
11167
  return;
11168
11168
  }
11169
11169
  if (workspaceMode) {
11170
- const { cmdWorkspace } = await import("./workspace-47XLOUGD.js");
11170
+ const { cmdWorkspace } = await import("./workspace-QAZ3F4VT.js");
11171
11171
  await cmdWorkspace(process.cwd(), ["workspace", "health", ...withoutWorkflowOnlyFlags(args)]);
11172
11172
  return;
11173
11173
  }
@@ -11210,7 +11210,7 @@ async function cmdVerifyWorkflow(args) {
11210
11210
  process.exitCode = void 0;
11211
11211
  }
11212
11212
  }
11213
- const { cmdHealth, parseHealthArgs } = await import("./health-RRIM7YAV.js");
11213
+ const { cmdHealth, parseHealthArgs } = await import("./health-KUPBUU3B.js");
11214
11214
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(healthArgs));
11215
11215
  if (localPatterns) {
11216
11216
  const validation = validateLocalLaw(workspaceInfo.appRoot);
@@ -12872,7 +12872,7 @@ async function main() {
12872
12872
  const { flags } = parseLooseArgs(args);
12873
12873
  const workspaceInfo = resolveWorkflowProject(flags, "health");
12874
12874
  if (!workspaceInfo) break;
12875
- const { cmdHealth, parseHealthArgs } = await import("./health-RRIM7YAV.js");
12875
+ const { cmdHealth, parseHealthArgs } = await import("./health-KUPBUU3B.js");
12876
12876
  await cmdHealth(workspaceInfo.appRoot, parseHealthArgs(stripProjectArgs(args)));
12877
12877
  } catch (e) {
12878
12878
  console.error(error2(e.message));
@@ -12900,7 +12900,7 @@ async function main() {
12900
12900
  cmdStudioHelp();
12901
12901
  break;
12902
12902
  }
12903
- const { cmdStudio, parseStudioArgs } = await import("./studio-RGXIJL3J.js");
12903
+ const { cmdStudio, parseStudioArgs } = await import("./studio-J6Z3AUAR.js");
12904
12904
  await cmdStudio(process.cwd(), parseStudioArgs(args));
12905
12905
  } catch (e) {
12906
12906
  console.error(error2(e.message));
@@ -12914,7 +12914,7 @@ async function main() {
12914
12914
  cmdWorkspaceHelp();
12915
12915
  break;
12916
12916
  }
12917
- const { cmdWorkspace } = await import("./workspace-47XLOUGD.js");
12917
+ const { cmdWorkspace } = await import("./workspace-QAZ3F4VT.js");
12918
12918
  await cmdWorkspace(process.cwd(), args);
12919
12919
  } catch (e) {
12920
12920
  console.error(error2(e.message));
@@ -60,7 +60,7 @@ function looksLikeApp(dir, options = {}) {
60
60
  const pkg = readPackageJson(dir);
61
61
  const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };
62
62
  const hasFrontendDependency = Boolean(
63
- deps.react || deps["react-dom"] || deps.next || deps.vue || deps.svelte || deps["@angular/core"] || deps.astro || deps.nuxt
63
+ deps.react || deps["react-dom"] || deps.next || deps["@remix-run/react"] || deps["@remix-run/dev"] || deps.vue || deps.svelte || deps["@angular/core"] || deps.astro || deps.nuxt || deps["solid-js"]
64
64
  );
65
65
  const hasServerOnlyDependency = Boolean(
66
66
  deps.hono || deps.express || deps.fastify || deps.koa || deps["@hapi/hapi"]
@@ -76,7 +76,86 @@ function looksLikeApp(dir, options = {}) {
76
76
  if (!allowPackageDeps) return false;
77
77
  return hasFrontendDependency;
78
78
  }
79
- function listWorkspaceApps(workspaceRoot) {
79
+ function hasConfig(dir) {
80
+ return 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")) || existsSync(join(dir, "remix.config.js")) || existsSync(join(dir, "remix.config.mjs")) || existsSync(join(dir, "remix.config.ts"));
81
+ }
82
+ function hasUiSource(dir) {
83
+ return existsSync(join(dir, "src")) || existsSync(join(dir, "app")) || existsSync(join(dir, "pages"));
84
+ }
85
+ function rankWorkspaceAppCandidate(workspaceRoot, base, name) {
86
+ const path = `${base}/${name}`;
87
+ const dir = join(workspaceRoot, path);
88
+ const pkg = readPackageJson(dir);
89
+ const deps = { ...pkg?.dependencies, ...pkg?.devDependencies };
90
+ const lowerPath = path.toLowerCase();
91
+ const reasons = [];
92
+ let score = base === "apps" ? 25 : -20;
93
+ if (base === "apps") reasons.push("under apps/");
94
+ if (base === "packages") reasons.push("under packages/");
95
+ const frontendDeps = [
96
+ "react",
97
+ "react-dom",
98
+ "next",
99
+ "@remix-run/react",
100
+ "@remix-run/dev",
101
+ "vue",
102
+ "svelte",
103
+ "@angular/core",
104
+ "astro",
105
+ "nuxt",
106
+ "solid-js"
107
+ ].filter((dep) => deps[dep]);
108
+ if (frontendDeps.length > 0) {
109
+ score += 30;
110
+ reasons.push(`frontend deps: ${frontendDeps.slice(0, 3).join(", ")}`);
111
+ }
112
+ if (hasConfig(dir)) {
113
+ score += 20;
114
+ reasons.push("frontend config");
115
+ }
116
+ if (hasUiSource(dir)) {
117
+ score += 10;
118
+ reasons.push("UI source tree");
119
+ }
120
+ if (/\b(web|app|dashboard|remix|client|frontend|site|portal)\b/u.test(lowerPath)) {
121
+ score += 25;
122
+ reasons.push("product-app name");
123
+ }
124
+ if (/\b(marketing|admin|console)\b/u.test(lowerPath)) {
125
+ score += 10;
126
+ reasons.push("taskable app surface");
127
+ }
128
+ const negativeSignals = [
129
+ [/\b(docs?|documentation)\b/u, 40, "docs surface"],
130
+ [/\bstorybook\b/u, 45, "Storybook surface"],
131
+ [/\b(api|server|backend|worker|queue)\b/u, 35, "server/API surface"],
132
+ [/\bmcp\b/u, 40, "MCP/helper surface"],
133
+ [/\b(workbench|playground|sandbox|example|demo)\b/u, 30, "workbench/demo surface"],
134
+ [
135
+ /\b(design-system|components?|ui|tokens?|theme|config|eslint|tsconfig)\b/u,
136
+ 30,
137
+ "library/config surface"
138
+ ]
139
+ ];
140
+ for (const [pattern, penalty, reason] of negativeSignals) {
141
+ if (!pattern.test(lowerPath)) continue;
142
+ score -= penalty;
143
+ reasons.push(reason);
144
+ }
145
+ const serverDeps = ["hono", "express", "fastify", "koa", "@hapi/hapi"].filter((dep) => deps[dep]);
146
+ if (serverDeps.length > 0 && frontendDeps.length === 0) {
147
+ score -= 35;
148
+ reasons.push(`server-only deps: ${serverDeps.slice(0, 2).join(", ")}`);
149
+ }
150
+ const category = score >= 65 ? "product-ui" : score >= 30 ? "supporting-ui" : "low-confidence-ui";
151
+ return {
152
+ path,
153
+ score,
154
+ category,
155
+ reason: reasons.join("; ") || "filesystem candidate"
156
+ };
157
+ }
158
+ function listWorkspaceAppDetails(workspaceRoot) {
80
159
  const candidates = [];
81
160
  for (const base of ["apps", "packages"]) {
82
161
  const baseDir = join(workspaceRoot, base);
@@ -88,14 +167,21 @@ function listWorkspaceApps(workspaceRoot) {
88
167
  allowSourceDirs: base === "apps",
89
168
  allowPackageDeps: base === "apps"
90
169
  })) {
91
- candidates.push(`${base}/${entry.name}`);
170
+ const ranked = rankWorkspaceAppCandidate(
171
+ workspaceRoot,
172
+ base,
173
+ entry.name
174
+ );
175
+ if (ranked.score <= 0) continue;
176
+ if (base === "packages" && ranked.category !== "product-ui") continue;
177
+ candidates.push(ranked);
92
178
  }
93
179
  }
94
180
  }
95
- return candidates.sort();
181
+ return candidates.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path));
96
182
  }
97
- function listWorkspaceAppCandidates(workspaceRoot) {
98
- return listWorkspaceApps(resolve(workspaceRoot));
183
+ function listWorkspaceAppCandidateDetails(workspaceRoot) {
184
+ return listWorkspaceAppDetails(resolve(workspaceRoot));
99
185
  }
100
186
  function resolveWorkspaceInfo(cwd, projectArg) {
101
187
  const absoluteCwd = resolve(cwd);
@@ -103,7 +189,8 @@ function resolveWorkspaceInfo(cwd, projectArg) {
103
189
  isAbsolute(projectArg) ? projectArg : join(findWorkspaceRoot(absoluteCwd) ?? absoluteCwd, projectArg)
104
190
  ) : absoluteCwd;
105
191
  const workspaceRoot = projectArg && isAbsolute(projectArg) ? findWorkspaceRoot(appRoot) ?? appRoot : findWorkspaceRoot(absoluteCwd) ?? absoluteCwd;
106
- const appCandidates = listWorkspaceApps(workspaceRoot);
192
+ const appCandidateDetails = listWorkspaceAppDetails(workspaceRoot);
193
+ const appCandidates = appCandidateDetails.map((candidate) => candidate.path);
107
194
  const projectScope = workspaceRoot !== appRoot || appCandidates.length > 0 ? "workspace-app" : "single-app";
108
195
  const requiresProjectSelection = !projectArg && workspaceRoot === absoluteCwd && appCandidates.length > 0;
109
196
  return {
@@ -112,6 +199,7 @@ function resolveWorkspaceInfo(cwd, projectArg) {
112
199
  appRoot,
113
200
  projectScope,
114
201
  appCandidates,
202
+ appCandidateDetails,
115
203
  requiresProjectSelection
116
204
  };
117
205
  }
@@ -5438,7 +5526,7 @@ export {
5438
5526
  acceptStyleBridge,
5439
5527
  createStyleBridgeTaskSummary,
5440
5528
  styleBridgeMatches,
5441
- listWorkspaceAppCandidates,
5529
+ listWorkspaceAppCandidateDetails,
5442
5530
  resolveWorkspaceInfo,
5443
5531
  buildGraphArtifacts,
5444
5532
  cmdGraphHelp,
@@ -13,7 +13,7 @@ import {
13
13
  renderProjectHealthCiWorkflow,
14
14
  shouldFailHealth,
15
15
  writeProjectHealthCiWorkflow
16
- } from "./chunk-U62GGKUO.js";
16
+ } from "./chunk-WAGVDMJV.js";
17
17
  import "./chunk-24JR4ZNG.js";
18
18
  export {
19
19
  cmdHealth,
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import "./chunk-4O74E2PS.js";
1
+ import "./chunk-TGVBWTDK.js";
2
2
  import "./chunk-SIDKK73N.js";
3
- import "./chunk-FIWVRMZN.js";
4
- import "./chunk-U62GGKUO.js";
3
+ import "./chunk-56HUEUO3.js";
4
+ import "./chunk-WAGVDMJV.js";
5
5
  import "./chunk-24JR4ZNG.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  createWorkspaceHealthReport
3
- } from "./chunk-FIWVRMZN.js";
3
+ } from "./chunk-56HUEUO3.js";
4
4
  import {
5
5
  createProjectHealthReport
6
- } from "./chunk-U62GGKUO.js";
6
+ } from "./chunk-WAGVDMJV.js";
7
7
  import {
8
8
  sendStudioHealthRefreshedTelemetry,
9
9
  sendStudioStartedTelemetry
@@ -7,8 +7,8 @@ import {
7
7
  listWorkspaceProjects,
8
8
  parseWorkspaceArgs,
9
9
  shouldFailWorkspaceHealth
10
- } from "./chunk-FIWVRMZN.js";
11
- import "./chunk-U62GGKUO.js";
10
+ } from "./chunk-56HUEUO3.js";
11
+ import "./chunk-WAGVDMJV.js";
12
12
  import "./chunk-24JR4ZNG.js";
13
13
  export {
14
14
  cmdWorkspace,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decantr/cli",
3
- "version": "3.5.5",
3
+ "version": "3.6.1",
4
4
  "description": "Decantr CLI - adopt, verify, graph, and govern frontend codebases touched by AI agents",
5
5
  "keywords": [
6
6
  "decantr",
@@ -49,11 +49,11 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "ajv": "^8.20.0",
52
- "@decantr/core": "3.5.0",
52
+ "@decantr/core": "3.6.0",
53
53
  "@decantr/essence-spec": "3.4.0",
54
54
  "@decantr/registry": "3.4.0",
55
55
  "@decantr/telemetry": "3.4.0",
56
- "@decantr/verifier": "3.5.5"
56
+ "@decantr/verifier": "3.6.1"
57
57
  },
58
58
  "scripts": {
59
59
  "build": "tsup",