@decantr/cli 2.8.0 → 2.8.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 +13 -4
- package/dist/bin.js +2 -1
- package/dist/{chunk-ICSLIYSX.js → chunk-FV6DGYD7.js} +49 -8
- package/dist/{chunk-QTPNV5WU.js → chunk-RKZMHS2K.js} +292 -240
- package/dist/chunk-VE6N3XWG.js +78 -0
- package/dist/index.js +2 -1
- package/dist/{studio-MKLBUC3A.js → studio-G3YOU5YF.js} +2 -1
- package/dist/{workspace-KSFWRZEX.js → workspace-U7J3CJY3.js} +4 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ Explicit workflow/adoption flags:
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
decantr setup
|
|
41
|
-
decantr adopt --
|
|
41
|
+
decantr adopt --yes
|
|
42
42
|
decantr codify --from-audit
|
|
43
43
|
decantr codify --accept
|
|
44
44
|
decantr task /feed "add saved recipe actions"
|
|
@@ -61,7 +61,14 @@ Adoption modes:
|
|
|
61
61
|
- `style-bridge` writes bridge tokens/files that map Decantr intent onto an existing style system without requiring `@decantr/css`.
|
|
62
62
|
- `decantr-css` writes the full Decantr CSS files and runtime guidance.
|
|
63
63
|
|
|
64
|
-
Monorepos store both `workspaceRoot` and `appRoot`.
|
|
64
|
+
Monorepos store both `workspaceRoot` and `appRoot`. Install Decantr at the workspace root if that is where dependencies are managed, but attach Decantr to an app root with `--project=<path>`.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pnpm add -D -w @decantr/cli
|
|
68
|
+
pnpm exec decantr setup
|
|
69
|
+
pnpm exec decantr workspace list
|
|
70
|
+
pnpm exec decantr adopt --project apps/web --yes
|
|
71
|
+
```
|
|
65
72
|
|
|
66
73
|
Assistant rule integration is preview-first: `--assistant-bridge=preview` writes `.decantr/context/assistant-bridge.md`, `decantr rules preview` prints the bridge, and `--assistant-bridge=apply` or `decantr rules apply` mutates supported rule files with idempotent marked blocks.
|
|
67
74
|
|
|
@@ -86,11 +93,13 @@ Brownfield analysis also writes `.decantr/doctrine-map.json`, a ranked source-pr
|
|
|
86
93
|
```bash
|
|
87
94
|
decantr setup
|
|
88
95
|
decantr new my-app --blueprint=esports-hq
|
|
89
|
-
decantr adopt --
|
|
96
|
+
decantr adopt --yes
|
|
97
|
+
decantr adopt --project apps/web --yes
|
|
90
98
|
decantr codify --from-audit
|
|
91
99
|
decantr codify --accept
|
|
92
100
|
decantr task /feed "add saved recipe actions"
|
|
93
101
|
decantr verify --brownfield --local-patterns
|
|
102
|
+
decantr verify --base-url http://localhost:3000 --evidence
|
|
94
103
|
decantr init --existing --blueprint=esports-hq
|
|
95
104
|
decantr init --workflow=greenfield --adoption=contract-only
|
|
96
105
|
decantr rules preview
|
|
@@ -151,7 +160,7 @@ Use `--json` for machines and schema validation, `--markdown` for CI summaries,
|
|
|
151
160
|
|
|
152
161
|
`decantr verify init-ci` installs `.github/workflows/decantr-health.yml` for GitHub Actions. The generated workflow installs project dependencies, writes JSON/markdown health artifacts, gates with the Project Health CI command, appends the markdown report to the GitHub step summary, and uploads both files as artifacts. Use `--force` to replace an existing workflow, `--fail-on warn` for stricter repositories, or `--cli-version <version|latest>` to pin the package used by CI. In monorepos, add `--project <path>` from the repository root; dependency install stays at the root while health runs inside the app contract and uploads artifacts from that project path. Use `--workspace` to generate an aggregate gate that runs `decantr workspace health` from the repository root and uploads `.decantr/workspace-health.json` plus `.decantr/workspace-health.md`.
|
|
153
162
|
|
|
154
|
-
`decantr workspace` is the monorepo reliability namespace.
|
|
163
|
+
`decantr workspace` is the monorepo reliability namespace. Before attach, `workspace list` shows app candidates. After attach, it also discovers Decantr projects from `.decantr/workspace.json` or by finding `decantr.essence.json` files. Workspace health runs projects with deterministic ordering, concurrency, per-project timeout, failure isolation, and aggregate JSON, and can limit a run to changed projects:
|
|
155
164
|
|
|
156
165
|
```bash
|
|
157
166
|
decantr workspace list
|
package/dist/bin.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listWorkspaceAppCandidates
|
|
3
|
+
} from "./chunk-VE6N3XWG.js";
|
|
1
4
|
import {
|
|
2
5
|
createProjectHealthReport
|
|
3
6
|
} from "./chunk-PAF4PBD3.js";
|
|
@@ -93,6 +96,14 @@ function listWorkspaceProjects(root = process.cwd()) {
|
|
|
93
96
|
}
|
|
94
97
|
return [...byPath.values()].sort((a, b) => a.path.localeCompare(b.path));
|
|
95
98
|
}
|
|
99
|
+
function listWorkspaceCandidates(root = process.cwd(), projects = listWorkspaceProjects(root)) {
|
|
100
|
+
const attached = new Set(projects.map((project) => project.path));
|
|
101
|
+
return listWorkspaceAppCandidates(root).map((path) => ({
|
|
102
|
+
path,
|
|
103
|
+
attached: attached.has(path),
|
|
104
|
+
suggestedAdoptCommand: `decantr adopt --project ${path} --yes`
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
96
107
|
function changedPaths(root, since) {
|
|
97
108
|
try {
|
|
98
109
|
const output = execFileSync("git", ["diff", "--name-only", since, "--"], {
|
|
@@ -100,7 +111,9 @@ function changedPaths(root, since) {
|
|
|
100
111
|
encoding: "utf-8",
|
|
101
112
|
stdio: ["ignore", "pipe", "ignore"]
|
|
102
113
|
});
|
|
103
|
-
return new Set(
|
|
114
|
+
return new Set(
|
|
115
|
+
output.split("\n").map((line) => line.trim()).filter(Boolean)
|
|
116
|
+
);
|
|
104
117
|
} catch {
|
|
105
118
|
return /* @__PURE__ */ new Set();
|
|
106
119
|
}
|
|
@@ -116,7 +129,10 @@ function projectChanged(project, changed) {
|
|
|
116
129
|
async function withTimeout(promise, timeoutMs, label) {
|
|
117
130
|
let timeout;
|
|
118
131
|
const timer = new Promise((_, reject) => {
|
|
119
|
-
timeout = setTimeout(
|
|
132
|
+
timeout = setTimeout(
|
|
133
|
+
() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)),
|
|
134
|
+
timeoutMs
|
|
135
|
+
);
|
|
120
136
|
});
|
|
121
137
|
try {
|
|
122
138
|
return await Promise.race([promise, timer]);
|
|
@@ -265,9 +281,11 @@ function parseWorkspaceArgs(args) {
|
|
|
265
281
|
else if (arg.startsWith("--since=")) options.since = arg.split("=")[1];
|
|
266
282
|
else if (arg === "--output" && args[index + 1]) options.output = args[++index];
|
|
267
283
|
else if (arg.startsWith("--output=")) options.output = arg.split("=")[1];
|
|
268
|
-
else if (arg === "--fail-on" && args[index + 1])
|
|
284
|
+
else if (arg === "--fail-on" && args[index + 1])
|
|
285
|
+
options.failOn = parseHealthFailOn(args[++index]);
|
|
269
286
|
else if (arg.startsWith("--fail-on=")) options.failOn = parseHealthFailOn(arg.split("=")[1]);
|
|
270
|
-
else if (arg === "--concurrency" && args[index + 1])
|
|
287
|
+
else if (arg === "--concurrency" && args[index + 1])
|
|
288
|
+
options.concurrency = Number(args[++index]);
|
|
271
289
|
else if (arg.startsWith("--concurrency=")) options.concurrency = Number(arg.split("=")[1]);
|
|
272
290
|
else if (arg === "--timeout-ms" && args[index + 1]) options.timeoutMs = Number(args[++index]);
|
|
273
291
|
else if (arg.startsWith("--timeout-ms=")) options.timeoutMs = Number(arg.split("=")[1]);
|
|
@@ -278,15 +296,36 @@ async function cmdWorkspace(workspaceRoot = process.cwd(), args = ["workspace"])
|
|
|
278
296
|
const options = parseWorkspaceArgs(args);
|
|
279
297
|
if (options.subcommand === "list") {
|
|
280
298
|
const projects = listWorkspaceProjects(workspaceRoot);
|
|
281
|
-
const
|
|
299
|
+
const candidates = listWorkspaceCandidates(workspaceRoot, projects);
|
|
300
|
+
const unattachedCandidates = candidates.filter((candidate) => !candidate.attached);
|
|
301
|
+
const payload2 = `${JSON.stringify({ projects, candidates }, null, 2)}
|
|
282
302
|
`;
|
|
283
303
|
if (options.json) {
|
|
284
304
|
process.stdout.write(payload2);
|
|
285
305
|
return;
|
|
286
306
|
}
|
|
287
307
|
console.log(`${BOLD}Decantr workspace projects${RESET}`);
|
|
288
|
-
|
|
289
|
-
|
|
308
|
+
console.log("");
|
|
309
|
+
console.log("Attached Decantr projects:");
|
|
310
|
+
if (projects.length === 0) {
|
|
311
|
+
console.log(` ${DIM}(none yet)${RESET}`);
|
|
312
|
+
} else {
|
|
313
|
+
for (const project of projects) {
|
|
314
|
+
console.log(` ${project.path} ${DIM}${project.source}${RESET}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (candidates.length > 0) {
|
|
318
|
+
console.log("");
|
|
319
|
+
console.log("App candidates:");
|
|
320
|
+
for (const candidate of candidates) {
|
|
321
|
+
const status = candidate.attached ? `${GREEN}attached${RESET}` : `${YELLOW}unattached${RESET}`;
|
|
322
|
+
console.log(` ${candidate.path} ${DIM}${status}${RESET}`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (unattachedCandidates.length > 0) {
|
|
326
|
+
console.log("");
|
|
327
|
+
console.log("Start by attaching one app:");
|
|
328
|
+
console.log(` ${unattachedCandidates[0].suggestedAdoptCommand}`);
|
|
290
329
|
}
|
|
291
330
|
return;
|
|
292
331
|
}
|
|
@@ -296,7 +335,8 @@ async function cmdWorkspace(workspaceRoot = process.cwd(), args = ["workspace"])
|
|
|
296
335
|
if (options.output) {
|
|
297
336
|
mkdirSync(dirname(resolve(workspaceRoot, options.output)), { recursive: true });
|
|
298
337
|
writeFileSync(resolve(workspaceRoot, options.output), payload, "utf-8");
|
|
299
|
-
if (!options.ci)
|
|
338
|
+
if (!options.ci)
|
|
339
|
+
console.log(`${GREEN}Wrote Decantr workspace health:${RESET} ${options.output}`);
|
|
300
340
|
} else {
|
|
301
341
|
process.stdout.write(payload);
|
|
302
342
|
}
|
|
@@ -307,6 +347,7 @@ async function cmdWorkspace(workspaceRoot = process.cwd(), args = ["workspace"])
|
|
|
307
347
|
|
|
308
348
|
export {
|
|
309
349
|
listWorkspaceProjects,
|
|
350
|
+
listWorkspaceCandidates,
|
|
310
351
|
createWorkspaceHealthReport,
|
|
311
352
|
formatWorkspaceHealthText,
|
|
312
353
|
formatWorkspaceHealthMarkdown,
|