@decantr/cli 2.3.1 → 2.4.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/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import "./chunk-2JWVKBNB.js";
2
- import "./chunk-WDA4SHIQ.js";
1
+ import "./chunk-6BRD6DTB.js";
2
+ import "./chunk-P4NUDLWB.js";
3
3
  import "./chunk-IEW2QFYI.js";
@@ -1,6 +1,9 @@
1
+ import {
2
+ createWorkspaceHealthReport
3
+ } from "./chunk-AUQXYJ7T.js";
1
4
  import {
2
5
  createProjectHealthReport
3
- } from "./chunk-3H3HWDJA.js";
6
+ } from "./chunk-OD46PCR6.js";
4
7
  import "./chunk-NBJCO4G5.js";
5
8
  import {
6
9
  sendStudioHealthRefreshedTelemetry,
@@ -1104,16 +1107,70 @@ function studioHtml(reportMode = false) {
1104
1107
  </body>
1105
1108
  </html>`;
1106
1109
  }
1110
+ function workspaceStudioHtml() {
1111
+ return `<!doctype html>
1112
+ <html lang="en">
1113
+ <head>
1114
+ <meta charset="utf-8">
1115
+ <meta name="viewport" content="width=device-width, initial-scale=1">
1116
+ <title>Decantr Workspace Health</title>
1117
+ <style>
1118
+ body { margin: 0; background: #101014; color: #f5f2eb; font-family: Inter, ui-sans-serif, system-ui, sans-serif; }
1119
+ header { padding: 1rem; border-bottom: 1px solid rgba(245,242,235,.12); display: flex; justify-content: space-between; gap: 1rem; align-items: center; }
1120
+ h1 { margin: 0; font-size: 1rem; }
1121
+ main { padding: 1rem; display: grid; gap: .75rem; }
1122
+ button { border: 1px solid rgba(245,242,235,.14); border-radius: 8px; background: rgba(245,242,235,.06); color: inherit; padding: .55rem .8rem; cursor: pointer; }
1123
+ .grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); border: 1px solid rgba(245,242,235,.1); border-radius: 8px; overflow: hidden; }
1124
+ .cell { padding: .7rem; border-bottom: 1px solid rgba(245,242,235,.08); }
1125
+ .head { color: #ada7bd; font-size: .75rem; text-transform: uppercase; }
1126
+ .healthy { color: #5ee2a0; } .warning { color: #f2bd61; } .error, .failed { color: #ff6f7d; }
1127
+ .card { border: 1px solid rgba(245,242,235,.1); border-radius: 8px; padding: 1rem; background: rgba(245,242,235,.025); }
1128
+ </style>
1129
+ </head>
1130
+ <body>
1131
+ <header><h1>Decantr Workspace Health</h1><button id="refresh">Refresh</button></header>
1132
+ <main id="root"><div class="card">Loading workspace health...</div></main>
1133
+ <script>
1134
+ const esc = (v) => String(v ?? '').replace(/[&<>"]/g, (ch) => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[ch]));
1135
+ async function load(refresh = false) {
1136
+ const res = await fetch(refresh ? '/api/workspace/refresh' : '/api/workspace', { method: refresh ? 'POST' : 'GET' });
1137
+ const report = await res.json();
1138
+ if (!res.ok) throw new Error(report.message || report.error || 'failed');
1139
+ const summary = report.summary || {};
1140
+ const rows = (report.projects || []).map((p) => '<div class="cell"><strong>' + esc(p.path) + '</strong></div><div class="cell ' + esc(p.status) + '">' + esc(p.status) + '</div><div class="cell">' + esc(p.score) + '</div><div class="cell">' + esc(p.findingCount) + '</div><div class="cell">' + esc(p.source) + '</div>').join('');
1141
+ document.getElementById('root').innerHTML =
1142
+ '<div class="card">Projects checked: <strong>' + esc(summary.checkedCount) + '/' + esc(summary.projectCount) + '</strong> \xB7 Healthy ' + esc(summary.healthyCount) + ' \xB7 Warnings ' + esc(summary.warningCount) + ' \xB7 Errors ' + esc(summary.errorCount) + ' \xB7 Failed ' + esc(summary.failedCount) + '</div>' +
1143
+ '<div class="grid"><div class="cell head">Project</div><div class="cell head">Status</div><div class="cell head">Score</div><div class="cell head">Findings</div><div class="cell head">Source</div>' + rows + '</div>';
1144
+ }
1145
+ document.getElementById('refresh').addEventListener('click', () => load(true).catch((e) => alert(e.message)));
1146
+ load().catch((e) => document.getElementById('root').innerHTML = '<div class="card error">' + esc(e.message) + '</div>');
1147
+ </script>
1148
+ </body>
1149
+ </html>`;
1150
+ }
1107
1151
  function createStudioRequestHandler(projectRoot, options = {}) {
1108
1152
  const reportPath = resolveReportPath(projectRoot, options.report);
1109
1153
  const loadReport = () => reportPath ? readProjectHealthReport(reportPath) : createProjectHealthReport(projectRoot);
1154
+ const loadWorkspaceReport = () => createWorkspaceHealthReport(projectRoot);
1110
1155
  return async function handleStudioRequest(req, res) {
1111
1156
  const url = new URL(req.url ?? "/", "http://localhost");
1112
1157
  try {
1113
1158
  if (req.method === "GET" && url.pathname === "/") {
1159
+ if (options.workspace) {
1160
+ sendHtml(res, workspaceStudioHtml());
1161
+ return;
1162
+ }
1114
1163
  sendHtml(res, studioHtml(Boolean(reportPath)));
1115
1164
  return;
1116
1165
  }
1166
+ if (options.workspace && req.method === "GET" && url.pathname === "/api/workspace") {
1167
+ sendJson(res, 200, await loadWorkspaceReport());
1168
+ return;
1169
+ }
1170
+ if (options.workspace && req.method === "POST" && url.pathname === "/api/workspace/refresh") {
1171
+ sendJson(res, 200, await loadWorkspaceReport());
1172
+ return;
1173
+ }
1117
1174
  if (req.method === "GET" && url.pathname === "/api/health") {
1118
1175
  sendJson(res, 200, await loadReport());
1119
1176
  return;
@@ -1164,6 +1221,9 @@ async function cmdStudio(projectRoot = process.cwd(), options = {}) {
1164
1221
  if (options.report) {
1165
1222
  console.log("Report mode enabled. Refresh re-reads the local Project Health JSON file.");
1166
1223
  }
1224
+ if (options.workspace) {
1225
+ console.log("Workspace mode enabled. Studio aggregates Decantr project health locally.");
1226
+ }
1167
1227
  console.log("Press Ctrl+C to stop.");
1168
1228
  }
1169
1229
  function parseStudioArgs(args) {
@@ -1187,6 +1247,8 @@ function parseStudioArgs(args) {
1187
1247
  const value = arg.slice("--report=".length);
1188
1248
  if (!value) throw new Error("Missing --report value.");
1189
1249
  options.report = value;
1250
+ } else if (arg === "--workspace") {
1251
+ options.workspace = true;
1190
1252
  }
1191
1253
  }
1192
1254
  if (options.port !== void 0 && (!Number.isInteger(options.port) || options.port < 0)) {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  RegistryClient,
3
3
  refreshDerivedFiles
4
- } from "./chunk-WDA4SHIQ.js";
4
+ } from "./chunk-P4NUDLWB.js";
5
5
 
6
6
  // src/commands/upgrade.ts
7
7
  import { existsSync, readFileSync, writeFileSync } from "fs";
@@ -0,0 +1,21 @@
1
+ import {
2
+ cmdWorkspace,
3
+ createWorkspaceHealthReport,
4
+ formatWorkspaceHealthMarkdown,
5
+ formatWorkspaceHealthText,
6
+ listWorkspaceProjects,
7
+ parseWorkspaceArgs,
8
+ shouldFailWorkspaceHealth
9
+ } from "./chunk-AUQXYJ7T.js";
10
+ import "./chunk-OD46PCR6.js";
11
+ import "./chunk-NBJCO4G5.js";
12
+ import "./chunk-IEW2QFYI.js";
13
+ export {
14
+ cmdWorkspace,
15
+ createWorkspaceHealthReport,
16
+ formatWorkspaceHealthMarkdown,
17
+ formatWorkspaceHealthText,
18
+ listWorkspaceProjects,
19
+ parseWorkspaceArgs,
20
+ shouldFailWorkspaceHealth
21
+ };
package/package.json CHANGED
@@ -1,7 +1,24 @@
1
1
  {
2
2
  "name": "@decantr/cli",
3
- "version": "2.3.1",
3
+ "version": "2.4.1",
4
4
  "description": "Decantr CLI - scaffold, audit, inspect Project Health, and maintain Decantr projects from the terminal",
5
+ "keywords": [
6
+ "decantr",
7
+ "decantr-ai",
8
+ "ai-coding",
9
+ "ai-generated-ui",
10
+ "cli",
11
+ "project-health",
12
+ "design-intelligence",
13
+ "design-governance",
14
+ "ui-verification",
15
+ "drift-detection",
16
+ "scaffolding",
17
+ "brownfield",
18
+ "cursor",
19
+ "claude-code",
20
+ "windsurf"
21
+ ],
5
22
  "author": "Decantr AI",
6
23
  "license": "MIT",
7
24
  "bugs": {
@@ -31,11 +48,11 @@
31
48
  },
32
49
  "dependencies": {
33
50
  "ajv": "^8.20.0",
34
- "@decantr/core": "2.0.0",
35
- "@decantr/telemetry": "2.2.1",
51
+ "@decantr/core": "2.1.0",
52
+ "@decantr/registry": "2.0.0",
36
53
  "@decantr/essence-spec": "2.0.1",
37
- "@decantr/verifier": "2.0.0",
38
- "@decantr/registry": "2.0.0"
54
+ "@decantr/telemetry": "2.2.1",
55
+ "@decantr/verifier": "2.1.0"
39
56
  },
40
57
  "scripts": {
41
58
  "build": "tsup",
@@ -38,10 +38,10 @@ jobs:
38
38
  fi
39
39
 
40
40
  - name: Generate Decantr health JSON
41
- {{PROJECT_WORKING_DIRECTORY}} run: npx --yes {{CLI_PACKAGE}} health --json --output {{JSON_PATH}}
41
+ {{PROJECT_WORKING_DIRECTORY}} run: npx --yes {{CLI_PACKAGE}} {{HEALTH_COMMAND}} --json --output {{JSON_PATH}}
42
42
 
43
43
  - name: Audit Decantr health
44
- {{PROJECT_WORKING_DIRECTORY}} run: npx --yes {{CLI_PACKAGE}} health --ci --fail-on {{FAIL_ON}} --markdown --output {{REPORT_PATH}}
44
+ {{PROJECT_WORKING_DIRECTORY}} run: npx --yes {{CLI_PACKAGE}} {{HEALTH_COMMAND}} --ci --fail-on {{FAIL_ON}} --markdown --output {{REPORT_PATH}}
45
45
 
46
46
  - name: Publish health summary
47
47
  if: always()