@docyrus/cli 0.4.0 → 0.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/README.md +17 -0
- package/dist/cli.js +773 -43
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -6,15 +6,15 @@ import { RestApiClient, AuthenticationError as AuthenticationError$1 } from '@do
|
|
|
6
6
|
import { createServer } from 'http';
|
|
7
7
|
import { randomBytes, createDecipheriv, createCipheriv, scryptSync, createHash } from 'crypto';
|
|
8
8
|
import open from 'open';
|
|
9
|
-
import { existsSync, readFileSync, mkdirSync, writeFileSync, unlinkSync, constants as constants$1 } from 'fs';
|
|
9
|
+
import { existsSync, readFileSync, readdirSync, mkdirSync, writeFileSync, unlinkSync, constants as constants$1 } from 'fs';
|
|
10
10
|
import { homedir, arch, release, platform, hostname, userInfo } from 'os';
|
|
11
11
|
import Conf from 'conf';
|
|
12
12
|
import chalk4 from 'chalk';
|
|
13
|
-
import
|
|
14
|
-
import { select, input, password, confirm } from '@inquirer/prompts';
|
|
13
|
+
import ora2 from 'ora';
|
|
14
|
+
import { select, input, password, confirm, checkbox } from '@inquirer/prompts';
|
|
15
15
|
import { exec, execFileSync } from 'child_process';
|
|
16
16
|
import { promisify } from 'util';
|
|
17
|
-
import { access, constants, writeFile, readFile, mkdir, cp, rm, readdir } from 'fs/promises';
|
|
17
|
+
import { access, constants, writeFile, readFile, mkdir, chmod, cp, rm, readdir } from 'fs/promises';
|
|
18
18
|
import { downloadTemplate } from 'giget';
|
|
19
19
|
import { generateFromOpenAPI } from '@docyrus/tanstack-db-generator';
|
|
20
20
|
|
|
@@ -57,12 +57,12 @@ var init_esm_shims = __esm({
|
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
59
|
|
|
60
|
-
// ../../node_modules/.pnpm/dotenv@17.
|
|
60
|
+
// ../../node_modules/.pnpm/dotenv@17.3.1/node_modules/dotenv/package.json
|
|
61
61
|
var require_package = __commonJS({
|
|
62
|
-
"../../node_modules/.pnpm/dotenv@17.
|
|
62
|
+
"../../node_modules/.pnpm/dotenv@17.3.1/node_modules/dotenv/package.json"(exports$1, module) {
|
|
63
63
|
module.exports = {
|
|
64
64
|
name: "dotenv",
|
|
65
|
-
version: "17.
|
|
65
|
+
version: "17.3.1",
|
|
66
66
|
description: "Loads environment variables from .env file",
|
|
67
67
|
main: "lib/main.js",
|
|
68
68
|
types: "lib/main.d.ts",
|
|
@@ -125,9 +125,9 @@ var require_package = __commonJS({
|
|
|
125
125
|
}
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
-
// ../../node_modules/.pnpm/dotenv@17.
|
|
128
|
+
// ../../node_modules/.pnpm/dotenv@17.3.1/node_modules/dotenv/lib/main.js
|
|
129
129
|
var require_main = __commonJS({
|
|
130
|
-
"../../node_modules/.pnpm/dotenv@17.
|
|
130
|
+
"../../node_modules/.pnpm/dotenv@17.3.1/node_modules/dotenv/lib/main.js"(exports$1, module) {
|
|
131
131
|
init_esm_shims();
|
|
132
132
|
var fs = __require("fs");
|
|
133
133
|
var path2 = __require("path");
|
|
@@ -139,12 +139,9 @@ var require_main = __commonJS({
|
|
|
139
139
|
"\u{1F510} encrypt with Dotenvx: https://dotenvx.com",
|
|
140
140
|
"\u{1F510} prevent committing .env to code: https://dotenvx.com/precommit",
|
|
141
141
|
"\u{1F510} prevent building .env in docker: https://dotenvx.com/prebuild",
|
|
142
|
-
"\u{
|
|
143
|
-
"\
|
|
144
|
-
"\u{
|
|
145
|
-
"\u2705 audit secrets and track compliance: https://dotenvx.com/ops",
|
|
146
|
-
"\u{1F504} add secrets lifecycle management: https://dotenvx.com/ops",
|
|
147
|
-
"\u{1F511} add access controls to secrets: https://dotenvx.com/ops",
|
|
142
|
+
"\u{1F916} agentic secret storage: https://dotenvx.com/as2",
|
|
143
|
+
"\u26A1\uFE0F secrets for agents: https://dotenvx.com/as2",
|
|
144
|
+
"\u{1F6E1}\uFE0F auth for agents: https://vestauth.com",
|
|
148
145
|
"\u{1F6E0}\uFE0F run anywhere with `dotenvx run -- yourcommand`",
|
|
149
146
|
"\u2699\uFE0F specify custom .env file path with { path: '/custom/path/.env' }",
|
|
150
147
|
"\u2699\uFE0F enable debug logging with { debug: true }",
|
|
@@ -1310,7 +1307,8 @@ init_esm_shims();
|
|
|
1310
1307
|
// src/config/config-manager.ts
|
|
1311
1308
|
init_esm_shims();
|
|
1312
1309
|
var defaults = {
|
|
1313
|
-
telemetryEnabled: true
|
|
1310
|
+
telemetryEnabled: true,
|
|
1311
|
+
helpTheme: "default"
|
|
1314
1312
|
};
|
|
1315
1313
|
var ConfigManager = class {
|
|
1316
1314
|
config;
|
|
@@ -1551,13 +1549,43 @@ var MESSAGES = {
|
|
|
1551
1549
|
ADD_MISSING_CONFIG: "components.json not found.",
|
|
1552
1550
|
ADD_MISSING_CONFIG_HINT: "Run `npx shadcn@latest init` first to initialize your project.",
|
|
1553
1551
|
ADD_DETECTED_STYLE: (style) => `Detected style: ${style}`,
|
|
1554
|
-
ADD_DEPRECATED_BASE_STYLE: 'Your components.json uses a deprecated "base-*" style. The radix/base variant distinction has been removed. All components now use the unified registry (@docyrus/ui-*).'
|
|
1552
|
+
ADD_DEPRECATED_BASE_STYLE: 'Your components.json uses a deprecated "base-*" style. The radix/base variant distinction has been removed. All components now use the unified registry (@docyrus/ui-*).',
|
|
1553
|
+
// List command
|
|
1554
|
+
LIST_HEADER: "Available Docyrus UI registry items:",
|
|
1555
|
+
LIST_FETCHING: "Fetching registry index...",
|
|
1556
|
+
LIST_FETCHING_NPM: "Fetching @docyrus npm packages...",
|
|
1557
|
+
LIST_NPM_SUCCESS: "Fetched npm packages",
|
|
1558
|
+
LIST_INSTALL_HINT: "Install with: docyrus add <name>",
|
|
1559
|
+
LIST_NPM_HEADER: "Published @docyrus npm packages:",
|
|
1560
|
+
LIST_NPM_LINK: "https://www.npmjs.com/settings/docyrus/packages",
|
|
1561
|
+
// Commitlint command
|
|
1562
|
+
COMMITLINT_DESCRIPTION: "Set up commitlint, husky, and lint-staged in your project",
|
|
1563
|
+
COMMITLINT_NO_PROJECT: "Could not find a package.json.",
|
|
1564
|
+
COMMITLINT_NO_PROJECT_HINT: "Run this command from within a JavaScript/TypeScript project.",
|
|
1565
|
+
COMMITLINT_IS_MONOREPO: "Is this a monorepo?",
|
|
1566
|
+
COMMITLINT_DETECTED_WORKSPACES: (count) => `Detected ${count} workspace(s)`,
|
|
1567
|
+
COMMITLINT_NO_WORKSPACES: "No workspaces detected. Enter scopes manually.",
|
|
1568
|
+
COMMITLINT_SCOPE_STRATEGY: "How should scopes be used?",
|
|
1569
|
+
COMMITLINT_SELECT_SCOPES: "Select scopes to include:",
|
|
1570
|
+
COMMITLINT_ADDITIONAL_SCOPES: "Enter additional scopes (comma-separated, or leave empty):",
|
|
1571
|
+
COMMITLINT_CONFIRM_SCOPES: (scopes) => `Scopes: ${scopes.join(", ")}`,
|
|
1572
|
+
COMMITLINT_CONFIG_EXISTS: "commitlint.config.ts already exists. Overwrite?",
|
|
1573
|
+
COMMITLINT_HUSKY_EXISTS: ".husky/ directory already exists. Overwrite hooks?",
|
|
1574
|
+
COMMITLINT_STEP_CONFIG: "Creating commitlint.config.ts",
|
|
1575
|
+
COMMITLINT_STEP_HUSKY: "Setting up Husky hooks",
|
|
1576
|
+
COMMITLINT_STEP_SCRIPT: "Creating commit-linter.sh script",
|
|
1577
|
+
COMMITLINT_STEP_PACKAGE_JSON: "Updating package.json",
|
|
1578
|
+
COMMITLINT_STEP_INSTALL: "Installing dependencies",
|
|
1579
|
+
COMMITLINT_STEP_INIT_HUSKY: "Initializing Husky",
|
|
1580
|
+
COMMITLINT_SUCCESS: "Commitlint setup complete!",
|
|
1581
|
+
COMMITLINT_SUCCESS_HINT: "Your commits will now be validated against Conventional Commits format.",
|
|
1582
|
+
COMMITLINT_DETECTED_PM: (pm) => `Package manager: ${pm}`
|
|
1555
1583
|
};
|
|
1556
1584
|
|
|
1557
1585
|
// src/ui/spinner.ts
|
|
1558
1586
|
init_esm_shims();
|
|
1559
1587
|
function createSpinner(text) {
|
|
1560
|
-
return
|
|
1588
|
+
return ora2({
|
|
1561
1589
|
text,
|
|
1562
1590
|
spinner: "dots"
|
|
1563
1591
|
});
|
|
@@ -1614,12 +1642,77 @@ async function promptPassword() {
|
|
|
1614
1642
|
|
|
1615
1643
|
// src/ui/progress.ts
|
|
1616
1644
|
init_esm_shims();
|
|
1617
|
-
|
|
1645
|
+
var SYMBOLS = {
|
|
1618
1646
|
pending: chalk4.dim("\u25CB"),
|
|
1619
1647
|
in_progress: chalk4.cyan("\u25D0"),
|
|
1620
1648
|
completed: chalk4.green("\u2713"),
|
|
1621
1649
|
failed: chalk4.red("\u2717")
|
|
1622
|
-
}
|
|
1650
|
+
};
|
|
1651
|
+
function createMultiStepProgress(title, stepLabels) {
|
|
1652
|
+
const steps = stepLabels.map((label) => ({
|
|
1653
|
+
label,
|
|
1654
|
+
status: "pending"
|
|
1655
|
+
}));
|
|
1656
|
+
let spinner = null;
|
|
1657
|
+
let currentStep = -1;
|
|
1658
|
+
const render = () => {
|
|
1659
|
+
console.log();
|
|
1660
|
+
console.log(chalk4.bold(title));
|
|
1661
|
+
console.log();
|
|
1662
|
+
for (const step of steps) {
|
|
1663
|
+
const symbol = SYMBOLS[step.status];
|
|
1664
|
+
const text = step.status === "in_progress" ? chalk4.cyan(step.label) : step.status === "completed" ? chalk4.green(step.label) : step.status === "failed" ? chalk4.red(step.label) : chalk4.dim(step.label);
|
|
1665
|
+
console.log(` ${symbol} ${text}`);
|
|
1666
|
+
if (step.status === "failed" && step.error) {
|
|
1667
|
+
console.log(` ${chalk4.red(step.error)}`);
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
console.log();
|
|
1671
|
+
};
|
|
1672
|
+
return {
|
|
1673
|
+
start(stepIndex) {
|
|
1674
|
+
if (stepIndex < 0 || stepIndex >= steps.length) return;
|
|
1675
|
+
if (spinner) {
|
|
1676
|
+
spinner.stop();
|
|
1677
|
+
}
|
|
1678
|
+
currentStep = stepIndex;
|
|
1679
|
+
steps[stepIndex].status = "in_progress";
|
|
1680
|
+
spinner = ora2({
|
|
1681
|
+
text: steps[stepIndex].label,
|
|
1682
|
+
color: "cyan"
|
|
1683
|
+
}).start();
|
|
1684
|
+
},
|
|
1685
|
+
complete(stepIndex) {
|
|
1686
|
+
if (stepIndex < 0 || stepIndex >= steps.length) return;
|
|
1687
|
+
if (spinner && currentStep === stepIndex) {
|
|
1688
|
+
spinner.succeed(chalk4.green(steps[stepIndex].label));
|
|
1689
|
+
spinner = null;
|
|
1690
|
+
}
|
|
1691
|
+
steps[stepIndex].status = "completed";
|
|
1692
|
+
},
|
|
1693
|
+
fail(stepIndex, error) {
|
|
1694
|
+
if (stepIndex < 0 || stepIndex >= steps.length) return;
|
|
1695
|
+
if (spinner && currentStep === stepIndex) {
|
|
1696
|
+
spinner.fail(chalk4.red(steps[stepIndex].label));
|
|
1697
|
+
spinner = null;
|
|
1698
|
+
}
|
|
1699
|
+
steps[stepIndex].status = "failed";
|
|
1700
|
+
steps[stepIndex].error = error;
|
|
1701
|
+
},
|
|
1702
|
+
update(stepIndex, message) {
|
|
1703
|
+
if (spinner && currentStep === stepIndex) {
|
|
1704
|
+
spinner.text = message;
|
|
1705
|
+
}
|
|
1706
|
+
},
|
|
1707
|
+
finish() {
|
|
1708
|
+
if (spinner) {
|
|
1709
|
+
spinner.stop();
|
|
1710
|
+
spinner = null;
|
|
1711
|
+
}
|
|
1712
|
+
render();
|
|
1713
|
+
}
|
|
1714
|
+
};
|
|
1715
|
+
}
|
|
1623
1716
|
function createSimpleProgress() {
|
|
1624
1717
|
let spinner = null;
|
|
1625
1718
|
return (step, current, total) => {
|
|
@@ -1628,7 +1721,7 @@ function createSimpleProgress() {
|
|
|
1628
1721
|
spinner = null;
|
|
1629
1722
|
}
|
|
1630
1723
|
const text = current && total ? `${step} (${current}/${total})` : step;
|
|
1631
|
-
spinner =
|
|
1724
|
+
spinner = ora2({
|
|
1632
1725
|
text,
|
|
1633
1726
|
color: "cyan"
|
|
1634
1727
|
}).start();
|
|
@@ -1639,6 +1732,71 @@ function createSimpleProgress() {
|
|
|
1639
1732
|
};
|
|
1640
1733
|
}
|
|
1641
1734
|
|
|
1735
|
+
// src/ui/help.ts
|
|
1736
|
+
init_esm_shims();
|
|
1737
|
+
var palettes = {
|
|
1738
|
+
default: {
|
|
1739
|
+
title: (str) => chalk4.bold.cyan(str),
|
|
1740
|
+
usage: (str) => chalk4.yellow(str),
|
|
1741
|
+
command: (str) => chalk4.green(str),
|
|
1742
|
+
argument: (str) => chalk4.magenta(str),
|
|
1743
|
+
description: (str) => chalk4.dim(str)
|
|
1744
|
+
},
|
|
1745
|
+
monochrome: {
|
|
1746
|
+
title: (str) => chalk4.bold(str),
|
|
1747
|
+
usage: (str) => chalk4.bold(str),
|
|
1748
|
+
command: (str) => chalk4.white(str),
|
|
1749
|
+
argument: (str) => chalk4.underline(str),
|
|
1750
|
+
description: (str) => chalk4.dim(str)
|
|
1751
|
+
},
|
|
1752
|
+
warm: {
|
|
1753
|
+
title: (str) => chalk4.bold.yellow(str),
|
|
1754
|
+
usage: (str) => chalk4.bold.red(str),
|
|
1755
|
+
command: (str) => chalk4.yellow(str),
|
|
1756
|
+
argument: (str) => chalk4.red(str),
|
|
1757
|
+
description: (str) => chalk4.dim(str)
|
|
1758
|
+
},
|
|
1759
|
+
cool: {
|
|
1760
|
+
title: (str) => chalk4.bold.blue(str),
|
|
1761
|
+
usage: (str) => chalk4.cyan(str),
|
|
1762
|
+
command: (str) => chalk4.blue(str),
|
|
1763
|
+
argument: (str) => chalk4.cyan(str),
|
|
1764
|
+
description: (str) => chalk4.dim(str)
|
|
1765
|
+
},
|
|
1766
|
+
neon: {
|
|
1767
|
+
title: (str) => chalk4.bold.magenta(str),
|
|
1768
|
+
usage: (str) => chalk4.cyan(str),
|
|
1769
|
+
command: (str) => chalk4.green(str),
|
|
1770
|
+
argument: (str) => chalk4.yellow(str),
|
|
1771
|
+
description: (str) => chalk4.dim(str)
|
|
1772
|
+
}
|
|
1773
|
+
};
|
|
1774
|
+
var HELP_THEMES = [
|
|
1775
|
+
"default",
|
|
1776
|
+
"monochrome",
|
|
1777
|
+
"warm",
|
|
1778
|
+
"cool",
|
|
1779
|
+
"neon"
|
|
1780
|
+
];
|
|
1781
|
+
function previewTheme(theme) {
|
|
1782
|
+
const p = palettes[theme];
|
|
1783
|
+
return `${p.title("Commands:")} ${p.command("add")} ${p.argument("<name>")} ${p.description("description")}`;
|
|
1784
|
+
}
|
|
1785
|
+
function getHelpConfig(theme = "default") {
|
|
1786
|
+
const p = palettes[theme];
|
|
1787
|
+
return {
|
|
1788
|
+
sortSubcommands: true,
|
|
1789
|
+
sortOptions: true,
|
|
1790
|
+
styleTitle: p.title,
|
|
1791
|
+
styleUsage: p.usage,
|
|
1792
|
+
styleCommandText: p.command,
|
|
1793
|
+
styleOptionText: p.command,
|
|
1794
|
+
styleArgumentText: p.argument,
|
|
1795
|
+
styleSubcommandText: p.command,
|
|
1796
|
+
styleDescriptionText: p.description
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1642
1800
|
// src/commands/login.ts
|
|
1643
1801
|
async function handleCredentialLogin(email) {
|
|
1644
1802
|
const lastEmail = configManager.get("lastLoginEmail");
|
|
@@ -3049,7 +3207,7 @@ ${errorMessage}`
|
|
|
3049
3207
|
// src/commands/generate.ts
|
|
3050
3208
|
init_esm_shims();
|
|
3051
3209
|
function registerGenerateCommand(program2) {
|
|
3052
|
-
const generate = program2.command("generate").description("
|
|
3210
|
+
const generate = program2.command("generate").description("Generate code from OpenAPI specs (e.g. TanStack Query collections)");
|
|
3053
3211
|
generate.command("api-spec").description("Download OpenAPI specification from Docyrus API").option("-o, --output <path>", "Output file path", "openapi.json").action(async (options) => {
|
|
3054
3212
|
const token = await requireAuth();
|
|
3055
3213
|
const outputPath = resolve(options.output);
|
|
@@ -3238,11 +3396,11 @@ _${CLI_NAME}_completions() {
|
|
|
3238
3396
|
args=("\${COMP_WORDS[@]}")
|
|
3239
3397
|
|
|
3240
3398
|
# Commands
|
|
3241
|
-
type_list="login logout whoami create generate upgrade completion info help"
|
|
3399
|
+
type_list="login logout whoami create add commitlint generate upgrade completion info help"
|
|
3242
3400
|
|
|
3243
3401
|
# Subcommands for generate
|
|
3244
3402
|
if [[ \${args[1]} == "generate" ]]; then
|
|
3245
|
-
type_list="db"
|
|
3403
|
+
type_list="api-spec db"
|
|
3246
3404
|
fi
|
|
3247
3405
|
|
|
3248
3406
|
COMPREPLY=($(compgen -W "\${type_list}" -- \${cur_word}))
|
|
@@ -3260,15 +3418,18 @@ _${CLI_NAME}() {
|
|
|
3260
3418
|
'logout:Log out from Docyrus'
|
|
3261
3419
|
'whoami:Display the current logged-in user'
|
|
3262
3420
|
'create:Create a new Docyrus project from template'
|
|
3263
|
-
'generate:
|
|
3421
|
+
'generate:Generate code from OpenAPI specs'
|
|
3264
3422
|
'upgrade:Upgrade Docyrus CLI to the latest version'
|
|
3265
3423
|
'completion:Generate shell completion script'
|
|
3424
|
+
'add:Add a component from the registry'
|
|
3425
|
+
'commitlint:Set up commitlint, husky, and lint-staged'
|
|
3266
3426
|
'info:Display CLI and environment information'
|
|
3267
3427
|
'help:Display help for command'
|
|
3268
3428
|
)
|
|
3269
3429
|
|
|
3270
3430
|
local -a generate_commands
|
|
3271
3431
|
generate_commands=(
|
|
3432
|
+
'api-spec:Download OpenAPI specification from Docyrus API'
|
|
3272
3433
|
'db:Generate TanStack Query collections from OpenAPI spec'
|
|
3273
3434
|
)
|
|
3274
3435
|
|
|
@@ -3301,13 +3462,16 @@ complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "login" -d "Log in to Docy
|
|
|
3301
3462
|
complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "logout" -d "Log out from Docyrus"
|
|
3302
3463
|
complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "whoami" -d "Display the current logged-in user"
|
|
3303
3464
|
complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "create" -d "Create a new Docyrus project"
|
|
3304
|
-
complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "generate" -d "
|
|
3465
|
+
complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "generate" -d "Generate code from OpenAPI specs"
|
|
3305
3466
|
complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "upgrade" -d "Upgrade Docyrus CLI"
|
|
3306
3467
|
complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "completion" -d "Generate shell completion"
|
|
3468
|
+
complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "add" -d "Add a component from the registry"
|
|
3469
|
+
complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "commitlint" -d "Set up commitlint and husky"
|
|
3307
3470
|
complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "info" -d "Display CLI and environment information"
|
|
3308
3471
|
complete -c ${CLI_NAME} -n "__fish_use_subcommand" -a "help" -d "Display help"
|
|
3309
3472
|
|
|
3310
3473
|
# generate subcommands
|
|
3474
|
+
complete -c ${CLI_NAME} -n "__fish_seen_subcommand_from generate" -a "api-spec" -d "Download OpenAPI specification"
|
|
3311
3475
|
complete -c ${CLI_NAME} -n "__fish_seen_subcommand_from generate" -a "db" -d "Generate TanStack Query collections"
|
|
3312
3476
|
###-end-${CLI_NAME}-completions-###
|
|
3313
3477
|
`.trim();
|
|
@@ -3407,18 +3571,37 @@ function registerInfoCommand(program2) {
|
|
|
3407
3571
|
|
|
3408
3572
|
// src/commands/config.ts
|
|
3409
3573
|
init_esm_shims();
|
|
3574
|
+
function showConfig(isLoggedIn, email, githubToken) {
|
|
3575
|
+
const currentTheme = configManager.get("helpTheme");
|
|
3576
|
+
logger.log("Current configuration:");
|
|
3577
|
+
logger.newline();
|
|
3578
|
+
logger.log(` Docyrus Login: ${isLoggedIn ? `\u2713 ${email}` : "\u2717 Not logged in"}`);
|
|
3579
|
+
logger.log(` Docyrus Token: ${githubToken ? "\u2713 Configured" : "\u2717 Not configured"}`);
|
|
3580
|
+
logger.log(` Help Theme: ${currentTheme}`);
|
|
3581
|
+
logger.newline();
|
|
3582
|
+
}
|
|
3410
3583
|
function registerConfigCommand(program2) {
|
|
3411
|
-
program2.command("config").description("Manage CLI configuration").option("--token", "Update Docyrus token for private template access").option("--show", "Show current configuration").action(async (options) => {
|
|
3584
|
+
program2.command("config").description("Manage CLI configuration").option("--token", "Update Docyrus token for private template access").option("--theme", "Change help output color theme").option("--show", "Show current configuration").action(async (options) => {
|
|
3412
3585
|
const tokenManager = getTokenManager();
|
|
3413
3586
|
if (options.show) {
|
|
3414
3587
|
const githubToken2 = await tokenManager.getGithubToken();
|
|
3415
3588
|
const isLoggedIn2 = await tokenManager.isLoggedIn();
|
|
3416
3589
|
const email2 = await tokenManager.getUserEmail();
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3590
|
+
showConfig(isLoggedIn2, email2, githubToken2);
|
|
3591
|
+
return;
|
|
3592
|
+
}
|
|
3593
|
+
if (options.theme) {
|
|
3594
|
+
const currentTheme = configManager.get("helpTheme");
|
|
3595
|
+
const theme = await select({
|
|
3596
|
+
message: "Select help color theme:",
|
|
3597
|
+
choices: HELP_THEMES.map((t) => ({
|
|
3598
|
+
name: `${t.padEnd(12)} ${previewTheme(t)}`,
|
|
3599
|
+
value: t
|
|
3600
|
+
})),
|
|
3601
|
+
default: currentTheme
|
|
3602
|
+
});
|
|
3603
|
+
configManager.set("helpTheme", theme);
|
|
3604
|
+
logger.success(`Help theme set to "${theme}"`);
|
|
3422
3605
|
return;
|
|
3423
3606
|
}
|
|
3424
3607
|
if (options.token) {
|
|
@@ -3441,12 +3624,9 @@ function registerConfigCommand(program2) {
|
|
|
3441
3624
|
const githubToken = await tokenManager.getGithubToken();
|
|
3442
3625
|
const isLoggedIn = await tokenManager.isLoggedIn();
|
|
3443
3626
|
const email = await tokenManager.getUserEmail();
|
|
3444
|
-
|
|
3445
|
-
logger.newline();
|
|
3446
|
-
logger.log(` Docyrus Login: ${isLoggedIn ? `\u2713 ${email}` : "\u2717 Not logged in"}`);
|
|
3447
|
-
logger.log(` Docyrus Token: ${githubToken ? "\u2713 Configured" : "\u2717 Not configured"}`);
|
|
3448
|
-
logger.newline();
|
|
3627
|
+
showConfig(isLoggedIn, email, githubToken);
|
|
3449
3628
|
logger.log("To update token: docyrus config --token");
|
|
3629
|
+
logger.log("To change theme: docyrus config --theme");
|
|
3450
3630
|
});
|
|
3451
3631
|
}
|
|
3452
3632
|
|
|
@@ -3480,11 +3660,11 @@ function detectPackageManager2(projectRoot) {
|
|
|
3480
3660
|
if (existsSync(join(projectRoot, "bun.lockb")) || existsSync(join(projectRoot, "bun.lock"))) return "bun";
|
|
3481
3661
|
return "npm";
|
|
3482
3662
|
}
|
|
3483
|
-
function normalizeRegistryName(
|
|
3484
|
-
if (
|
|
3485
|
-
if (
|
|
3486
|
-
if (
|
|
3487
|
-
return `@docyrus/ui-${
|
|
3663
|
+
function normalizeRegistryName(input4) {
|
|
3664
|
+
if (input4.startsWith("@docyrus/")) return input4;
|
|
3665
|
+
if (input4.startsWith("hooks-")) return `@docyrus/${input4}`;
|
|
3666
|
+
if (input4.startsWith("utils-")) return `@docyrus/${input4}`;
|
|
3667
|
+
return `@docyrus/ui-${input4}`;
|
|
3488
3668
|
}
|
|
3489
3669
|
async function fetchRegistryItem(name, token) {
|
|
3490
3670
|
const url = `${REGISTRY_BASE_URL}/${encodeURIComponent(name)}.json`;
|
|
@@ -3679,6 +3859,554 @@ Examples:
|
|
|
3679
3859
|
});
|
|
3680
3860
|
}
|
|
3681
3861
|
|
|
3862
|
+
// src/commands/commitlint.ts
|
|
3863
|
+
init_esm_shims();
|
|
3864
|
+
|
|
3865
|
+
// src/utils/commitlint-setup.ts
|
|
3866
|
+
init_esm_shims();
|
|
3867
|
+
function findProjectRoot2() {
|
|
3868
|
+
let dir = process.cwd();
|
|
3869
|
+
while (dir !== dirname(dir)) {
|
|
3870
|
+
if (existsSync(join(dir, "package.json"))) {
|
|
3871
|
+
return dir;
|
|
3872
|
+
}
|
|
3873
|
+
dir = dirname(dir);
|
|
3874
|
+
}
|
|
3875
|
+
throw new CliError(
|
|
3876
|
+
"Could not find a package.json.",
|
|
3877
|
+
1,
|
|
3878
|
+
"Run this command from within a JavaScript/TypeScript project."
|
|
3879
|
+
);
|
|
3880
|
+
}
|
|
3881
|
+
function detectPackageManager3(projectRoot) {
|
|
3882
|
+
if (existsSync(join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
3883
|
+
if (existsSync(join(projectRoot, "yarn.lock"))) return "yarn";
|
|
3884
|
+
if (existsSync(join(projectRoot, "bun.lockb")) || existsSync(join(projectRoot, "bun.lock"))) return "bun";
|
|
3885
|
+
return "npm";
|
|
3886
|
+
}
|
|
3887
|
+
async function detectWorkspaceScopes(projectRoot) {
|
|
3888
|
+
const scopes = /* @__PURE__ */ new Set();
|
|
3889
|
+
const pnpmPath = join(projectRoot, "pnpm-workspace.yaml");
|
|
3890
|
+
if (existsSync(pnpmPath)) {
|
|
3891
|
+
const content = await readFile(pnpmPath, "utf-8");
|
|
3892
|
+
const patterns = content.split("\n").filter((line) => line.trim().startsWith("-")).map((line) => line.trim().replace(/^-\s*['"]?/, "").replace(/['"]?\s*$/, ""));
|
|
3893
|
+
for (const pattern of patterns) {
|
|
3894
|
+
const baseDir = pattern.replace(/\/?\*+$/, "");
|
|
3895
|
+
const fullDir = join(projectRoot, baseDir);
|
|
3896
|
+
if (existsSync(fullDir)) {
|
|
3897
|
+
const entries = readdirSync(fullDir, { withFileTypes: true });
|
|
3898
|
+
for (const entry of entries) {
|
|
3899
|
+
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
3900
|
+
scopes.add(entry.name);
|
|
3901
|
+
}
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3906
|
+
try {
|
|
3907
|
+
const pkg = JSON.parse(await readFile(join(projectRoot, "package.json"), "utf-8"));
|
|
3908
|
+
const workspaces = Array.isArray(pkg.workspaces) ? pkg.workspaces : pkg.workspaces?.packages ?? [];
|
|
3909
|
+
for (const pattern of workspaces) {
|
|
3910
|
+
const baseDir = pattern.replace(/\/?\*+$/, "");
|
|
3911
|
+
const fullDir = join(projectRoot, baseDir);
|
|
3912
|
+
if (existsSync(fullDir)) {
|
|
3913
|
+
const entries = readdirSync(fullDir, { withFileTypes: true });
|
|
3914
|
+
for (const entry of entries) {
|
|
3915
|
+
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
3916
|
+
scopes.add(entry.name);
|
|
3917
|
+
}
|
|
3918
|
+
}
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3921
|
+
} catch {
|
|
3922
|
+
}
|
|
3923
|
+
scopes.add("root");
|
|
3924
|
+
scopes.add("deps");
|
|
3925
|
+
scopes.add("release");
|
|
3926
|
+
return [...scopes].sort();
|
|
3927
|
+
}
|
|
3928
|
+
function generateCommitlintConfig(opts) {
|
|
3929
|
+
const { scopes, scopeStrategy } = opts;
|
|
3930
|
+
let scopeRules = "";
|
|
3931
|
+
if (scopeStrategy === "required") {
|
|
3932
|
+
const scopeList = scopes.map((s) => `'${s}'`).join(", ");
|
|
3933
|
+
scopeRules = `
|
|
3934
|
+
// Scope required and must be from the allowed list
|
|
3935
|
+
'scope-case': [2, 'always', 'lower-case'],
|
|
3936
|
+
'scope-empty': [2, 'never'],
|
|
3937
|
+
'scope-enum': [2, 'always', [${scopeList}]],`;
|
|
3938
|
+
} else if (scopeStrategy === "optional") {
|
|
3939
|
+
const scopeList = scopes.map((s) => `'${s}'`).join(", ");
|
|
3940
|
+
scopeRules = `
|
|
3941
|
+
// Scope optional but if present must be from the allowed list
|
|
3942
|
+
'scope-case': [2, 'always', 'lower-case'],
|
|
3943
|
+
'scope-empty': [0],
|
|
3944
|
+
'scope-enum': [2, 'always', [${scopeList}]],`;
|
|
3945
|
+
}
|
|
3946
|
+
return `import { type UserConfig } from '@commitlint/types';
|
|
3947
|
+
|
|
3948
|
+
const config: UserConfig = {
|
|
3949
|
+
extends: ['@commitlint/config-conventional'],
|
|
3950
|
+
rules: {
|
|
3951
|
+
// Type required
|
|
3952
|
+
'type-empty': [2, 'never'],
|
|
3953
|
+
|
|
3954
|
+
// Subject required with length constraints
|
|
3955
|
+
'subject-empty': [2, 'never'],
|
|
3956
|
+
'subject-min-length': [2, 'always', 5],
|
|
3957
|
+
'subject-max-length': [2, 'always', 250],
|
|
3958
|
+
|
|
3959
|
+
// Header max length
|
|
3960
|
+
'header-max-length': [2, 'always', 100],
|
|
3961
|
+
${scopeRules}
|
|
3962
|
+
// Body (disabled \u2014 no line length limit)
|
|
3963
|
+
'body-max-line-length': [0, 'always', 200],
|
|
3964
|
+
|
|
3965
|
+
// BREAKING CHANGE (disabled by default)
|
|
3966
|
+
'trailer-exists': [0, 'always', 'BREAKING CHANGE']
|
|
3967
|
+
},
|
|
3968
|
+
|
|
3969
|
+
parserPreset: {
|
|
3970
|
+
parserOpts: {
|
|
3971
|
+
breakingHeaderPattern: /^(\\w*)(?:\\((.*)\\))?!: (.*)$/,
|
|
3972
|
+
noteKeywords: ['BREAKING CHANGE']
|
|
3973
|
+
}
|
|
3974
|
+
},
|
|
3975
|
+
|
|
3976
|
+
helpUrl:
|
|
3977
|
+
'https://github.com/conventional-changelog/commitlint/#what-is-commitlint'
|
|
3978
|
+
};
|
|
3979
|
+
|
|
3980
|
+
export default config;
|
|
3981
|
+
`;
|
|
3982
|
+
}
|
|
3983
|
+
function generateCommitMsgHook(packageManager) {
|
|
3984
|
+
const exec4 = packageManager === "pnpm" ? "pnpm exec" : packageManager === "yarn" ? "yarn" : packageManager === "bun" ? "bunx" : "npx --no-install";
|
|
3985
|
+
return `${exec4} commitlint --edit $1
|
|
3986
|
+
`;
|
|
3987
|
+
}
|
|
3988
|
+
function generatePreCommitHook() {
|
|
3989
|
+
return `# Skip if no code files are staged
|
|
3990
|
+
if git diff --cached --name-only | grep -qE '\\.(ts|tsx|js|jsx)$'; then
|
|
3991
|
+
npx --no-install lint-staged
|
|
3992
|
+
fi
|
|
3993
|
+
`;
|
|
3994
|
+
}
|
|
3995
|
+
function generateCommitLinterScript() {
|
|
3996
|
+
return `#!/usr/bin/env bash
|
|
3997
|
+
# Monorepo-aware tsc-files: finds the nearest tsconfig.json for each file,
|
|
3998
|
+
# groups files by their tsconfig directory, and runs tsc per group.
|
|
3999
|
+
|
|
4000
|
+
if [ $# -eq 0 ]; then
|
|
4001
|
+
exit 0
|
|
4002
|
+
fi
|
|
4003
|
+
|
|
4004
|
+
node -e "
|
|
4005
|
+
const fs = require('fs');
|
|
4006
|
+
const path = require('path');
|
|
4007
|
+
const { execFileSync } = require('child_process');
|
|
4008
|
+
|
|
4009
|
+
const files = process.argv.slice(1).map(f => path.resolve(f));
|
|
4010
|
+
const groups = {};
|
|
4011
|
+
|
|
4012
|
+
for (const file of files) {
|
|
4013
|
+
let dir = path.dirname(file);
|
|
4014
|
+
let tsconfigDir = null;
|
|
4015
|
+
|
|
4016
|
+
while (dir !== path.dirname(dir)) {
|
|
4017
|
+
if (fs.existsSync(path.join(dir, 'tsconfig.json'))) {
|
|
4018
|
+
tsconfigDir = dir;
|
|
4019
|
+
break;
|
|
4020
|
+
}
|
|
4021
|
+
dir = path.dirname(dir);
|
|
4022
|
+
}
|
|
4023
|
+
|
|
4024
|
+
if (!tsconfigDir) continue;
|
|
4025
|
+
if (!groups[tsconfigDir]) groups[tsconfigDir] = [];
|
|
4026
|
+
groups[tsconfigDir].push(file);
|
|
4027
|
+
}
|
|
4028
|
+
|
|
4029
|
+
let failed = false;
|
|
4030
|
+
|
|
4031
|
+
for (const [dir, groupFiles] of Object.entries(groups)) {
|
|
4032
|
+
const configPath = path.join(dir, 'tsconfig.json');
|
|
4033
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
4034
|
+
const tmpName = 'tsconfig.staged-' + process.pid + '.json';
|
|
4035
|
+
const tmpPath = path.join(dir, tmpName);
|
|
4036
|
+
|
|
4037
|
+
const excludePatterns = (config.exclude || []).map(p => p.replace(/\\\\/\\\\*\\\\*.*$/, '').replace(/\\\\/$/, ''));
|
|
4038
|
+
const filteredFiles = groupFiles.filter(f => {
|
|
4039
|
+
const rel = path.relative(dir, f).replace(/\\\\\\\\\\\\\\\\/g, '/');
|
|
4040
|
+
return !excludePatterns.some(p => rel === p || rel.startsWith(p + '/'));
|
|
4041
|
+
});
|
|
4042
|
+
if (filteredFiles.length === 0) continue;
|
|
4043
|
+
|
|
4044
|
+
const tmpConfig = {
|
|
4045
|
+
...config,
|
|
4046
|
+
compilerOptions: { ...config.compilerOptions, skipLibCheck: true, rootDir: undefined },
|
|
4047
|
+
files: filteredFiles,
|
|
4048
|
+
include: []
|
|
4049
|
+
};
|
|
4050
|
+
delete tmpConfig.compilerOptions.rootDir;
|
|
4051
|
+
|
|
4052
|
+
fs.writeFileSync(tmpPath, JSON.stringify(tmpConfig, null, 2));
|
|
4053
|
+
|
|
4054
|
+
try {
|
|
4055
|
+
execFileSync('npx', ['--no-install', 'tsc', '-p', tmpName, '--noEmit'], { cwd: dir, stdio: 'inherit' });
|
|
4056
|
+
} catch {
|
|
4057
|
+
failed = true;
|
|
4058
|
+
} finally {
|
|
4059
|
+
fs.unlinkSync(tmpPath);
|
|
4060
|
+
}
|
|
4061
|
+
}
|
|
4062
|
+
|
|
4063
|
+
if (failed) process.exit(1);
|
|
4064
|
+
" "$@"
|
|
4065
|
+
|
|
4066
|
+
exit $?
|
|
4067
|
+
`;
|
|
4068
|
+
}
|
|
4069
|
+
async function updatePackageJson(projectRoot) {
|
|
4070
|
+
const pkgPath = join(projectRoot, "package.json");
|
|
4071
|
+
const pkg = JSON.parse(await readFile(pkgPath, "utf-8"));
|
|
4072
|
+
pkg.devDependencies = {
|
|
4073
|
+
...pkg.devDependencies,
|
|
4074
|
+
"@commitlint/cli": "latest",
|
|
4075
|
+
"@commitlint/config-conventional": "latest",
|
|
4076
|
+
"@commitlint/types": "latest",
|
|
4077
|
+
husky: "latest",
|
|
4078
|
+
"lint-staged": "latest"
|
|
4079
|
+
};
|
|
4080
|
+
pkg.scripts = pkg.scripts ?? {};
|
|
4081
|
+
if (pkg.scripts.prepare && !pkg.scripts.prepare.includes("husky")) {
|
|
4082
|
+
pkg.scripts.prepare = `${pkg.scripts.prepare} && husky`;
|
|
4083
|
+
} else if (!pkg.scripts.prepare) {
|
|
4084
|
+
pkg.scripts.prepare = "husky";
|
|
4085
|
+
}
|
|
4086
|
+
pkg["lint-staged"] = {
|
|
4087
|
+
"*.{ts,tsx}": ["bash scripts/commit-linter.sh", "eslint --fix"]
|
|
4088
|
+
};
|
|
4089
|
+
await writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
4090
|
+
`, "utf-8");
|
|
4091
|
+
}
|
|
4092
|
+
async function writeCommitlintFiles(opts) {
|
|
4093
|
+
const {
|
|
4094
|
+
projectRoot,
|
|
4095
|
+
scopes,
|
|
4096
|
+
scopeStrategy,
|
|
4097
|
+
packageManager
|
|
4098
|
+
} = opts;
|
|
4099
|
+
await writeFile(
|
|
4100
|
+
join(projectRoot, "commitlint.config.ts"),
|
|
4101
|
+
generateCommitlintConfig({ scopes, scopeStrategy }),
|
|
4102
|
+
"utf-8"
|
|
4103
|
+
);
|
|
4104
|
+
const huskyDir = join(projectRoot, ".husky");
|
|
4105
|
+
if (!existsSync(huskyDir)) {
|
|
4106
|
+
await mkdir(huskyDir, { recursive: true });
|
|
4107
|
+
}
|
|
4108
|
+
await writeFile(join(huskyDir, "commit-msg"), generateCommitMsgHook(packageManager), "utf-8");
|
|
4109
|
+
await writeFile(join(huskyDir, "pre-commit"), generatePreCommitHook(), "utf-8");
|
|
4110
|
+
const scriptsDir = join(projectRoot, "scripts");
|
|
4111
|
+
if (!existsSync(scriptsDir)) {
|
|
4112
|
+
await mkdir(scriptsDir, { recursive: true });
|
|
4113
|
+
}
|
|
4114
|
+
const scriptPath = join(scriptsDir, "commit-linter.sh");
|
|
4115
|
+
await writeFile(scriptPath, generateCommitLinterScript(), "utf-8");
|
|
4116
|
+
await chmod(scriptPath, "755");
|
|
4117
|
+
}
|
|
4118
|
+
function installDeps(projectRoot, packageManager) {
|
|
4119
|
+
execFileSync(packageManager, ["install"], {
|
|
4120
|
+
cwd: projectRoot,
|
|
4121
|
+
stdio: "pipe"
|
|
4122
|
+
});
|
|
4123
|
+
}
|
|
4124
|
+
function initHusky(projectRoot, packageManager) {
|
|
4125
|
+
const cmds = {
|
|
4126
|
+
pnpm: ["pnpm", ["exec", "husky"]],
|
|
4127
|
+
npm: ["npx", ["husky"]],
|
|
4128
|
+
yarn: ["yarn", ["husky"]],
|
|
4129
|
+
bun: ["bunx", ["husky"]]
|
|
4130
|
+
};
|
|
4131
|
+
const [cmd, args] = cmds[packageManager];
|
|
4132
|
+
execFileSync(cmd, args, {
|
|
4133
|
+
cwd: projectRoot,
|
|
4134
|
+
stdio: "pipe"
|
|
4135
|
+
});
|
|
4136
|
+
}
|
|
4137
|
+
|
|
4138
|
+
// src/commands/commitlint.ts
|
|
4139
|
+
function registerCommitlintCommand(program2) {
|
|
4140
|
+
program2.command("commitlint").description(MESSAGES.COMMITLINT_DESCRIPTION).option("--scopes <scopes>", "Comma-separated list of scopes").option("--monorepo", "Treat as monorepo").option("--no-monorepo", "Treat as single project").option("--scope-strategy <strategy>", "Scope strategy: required, optional, none").option("-y, --yes", "Accept defaults and overwrite existing files").action(async (options) => {
|
|
4141
|
+
const projectRoot = findProjectRoot2();
|
|
4142
|
+
const packageManager = detectPackageManager3(projectRoot);
|
|
4143
|
+
logger.newline();
|
|
4144
|
+
logger.dim(MESSAGES.COMMITLINT_DETECTED_PM(packageManager));
|
|
4145
|
+
const configExists = existsSync(join(projectRoot, "commitlint.config.ts"));
|
|
4146
|
+
const huskyExists = existsSync(join(projectRoot, ".husky"));
|
|
4147
|
+
if (configExists && !options.yes) {
|
|
4148
|
+
const overwrite = await confirm({
|
|
4149
|
+
message: MESSAGES.COMMITLINT_CONFIG_EXISTS,
|
|
4150
|
+
default: false
|
|
4151
|
+
});
|
|
4152
|
+
if (!overwrite) {
|
|
4153
|
+
logger.dim("Aborted.");
|
|
4154
|
+
return;
|
|
4155
|
+
}
|
|
4156
|
+
}
|
|
4157
|
+
let skipHusky = false;
|
|
4158
|
+
if (huskyExists && !options.yes) {
|
|
4159
|
+
const overwrite = await confirm({
|
|
4160
|
+
message: MESSAGES.COMMITLINT_HUSKY_EXISTS,
|
|
4161
|
+
default: true
|
|
4162
|
+
});
|
|
4163
|
+
skipHusky = !overwrite;
|
|
4164
|
+
}
|
|
4165
|
+
const isMonorepo = options.monorepo !== void 0 ? options.monorepo : await confirm({
|
|
4166
|
+
message: MESSAGES.COMMITLINT_IS_MONOREPO,
|
|
4167
|
+
default: false
|
|
4168
|
+
});
|
|
4169
|
+
let scopeStrategy;
|
|
4170
|
+
if (options.scopeStrategy) {
|
|
4171
|
+
scopeStrategy = options.scopeStrategy;
|
|
4172
|
+
} else {
|
|
4173
|
+
scopeStrategy = await select({
|
|
4174
|
+
message: MESSAGES.COMMITLINT_SCOPE_STRATEGY,
|
|
4175
|
+
choices: [
|
|
4176
|
+
{
|
|
4177
|
+
name: isMonorepo ? "Required (recommended)" : "Required",
|
|
4178
|
+
value: "required",
|
|
4179
|
+
description: "fix(auth): ... \u2014 scope is mandatory"
|
|
4180
|
+
},
|
|
4181
|
+
{
|
|
4182
|
+
name: isMonorepo ? "Optional" : "Optional (recommended)",
|
|
4183
|
+
value: "optional",
|
|
4184
|
+
description: "fix: ... or fix(auth): ... \u2014 both valid"
|
|
4185
|
+
},
|
|
4186
|
+
{
|
|
4187
|
+
name: "None",
|
|
4188
|
+
value: "none",
|
|
4189
|
+
description: "fix: ... \u2014 scopes are not used"
|
|
4190
|
+
}
|
|
4191
|
+
],
|
|
4192
|
+
default: isMonorepo ? "required" : "optional"
|
|
4193
|
+
});
|
|
4194
|
+
}
|
|
4195
|
+
let scopes = [];
|
|
4196
|
+
if (scopeStrategy !== "none") {
|
|
4197
|
+
if (options.scopes) {
|
|
4198
|
+
scopes = options.scopes.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
4199
|
+
} else {
|
|
4200
|
+
if (isMonorepo) {
|
|
4201
|
+
const detected = await detectWorkspaceScopes(projectRoot);
|
|
4202
|
+
if (detected.length > 0) {
|
|
4203
|
+
logger.dim(MESSAGES.COMMITLINT_DETECTED_WORKSPACES(detected.length));
|
|
4204
|
+
scopes = await checkbox({
|
|
4205
|
+
message: MESSAGES.COMMITLINT_SELECT_SCOPES,
|
|
4206
|
+
choices: detected.map((s) => ({
|
|
4207
|
+
name: s,
|
|
4208
|
+
value: s,
|
|
4209
|
+
checked: true
|
|
4210
|
+
}))
|
|
4211
|
+
});
|
|
4212
|
+
} else {
|
|
4213
|
+
logger.warn(MESSAGES.COMMITLINT_NO_WORKSPACES);
|
|
4214
|
+
scopes = [
|
|
4215
|
+
"root",
|
|
4216
|
+
"deps",
|
|
4217
|
+
"release"
|
|
4218
|
+
];
|
|
4219
|
+
}
|
|
4220
|
+
} else {
|
|
4221
|
+
scopes = [
|
|
4222
|
+
"root",
|
|
4223
|
+
"deps",
|
|
4224
|
+
"release"
|
|
4225
|
+
];
|
|
4226
|
+
}
|
|
4227
|
+
const additional = await input({
|
|
4228
|
+
message: MESSAGES.COMMITLINT_ADDITIONAL_SCOPES
|
|
4229
|
+
});
|
|
4230
|
+
if (additional.trim()) {
|
|
4231
|
+
const extra = additional.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
4232
|
+
for (const s of extra) {
|
|
4233
|
+
if (!scopes.includes(s)) {
|
|
4234
|
+
scopes.push(s);
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4238
|
+
}
|
|
4239
|
+
scopes.sort();
|
|
4240
|
+
logger.newline();
|
|
4241
|
+
logger.info(MESSAGES.COMMITLINT_CONFIRM_SCOPES(scopes));
|
|
4242
|
+
}
|
|
4243
|
+
logger.newline();
|
|
4244
|
+
const progress = createMultiStepProgress("Setting up Commitlint", [
|
|
4245
|
+
MESSAGES.COMMITLINT_STEP_CONFIG,
|
|
4246
|
+
MESSAGES.COMMITLINT_STEP_HUSKY,
|
|
4247
|
+
MESSAGES.COMMITLINT_STEP_SCRIPT,
|
|
4248
|
+
MESSAGES.COMMITLINT_STEP_PACKAGE_JSON,
|
|
4249
|
+
MESSAGES.COMMITLINT_STEP_INSTALL,
|
|
4250
|
+
MESSAGES.COMMITLINT_STEP_INIT_HUSKY
|
|
4251
|
+
]);
|
|
4252
|
+
progress.start(0);
|
|
4253
|
+
await writeCommitlintFiles({
|
|
4254
|
+
projectRoot,
|
|
4255
|
+
scopes,
|
|
4256
|
+
scopeStrategy,
|
|
4257
|
+
packageManager
|
|
4258
|
+
});
|
|
4259
|
+
progress.complete(0);
|
|
4260
|
+
if (skipHusky) {
|
|
4261
|
+
progress.complete(1);
|
|
4262
|
+
} else {
|
|
4263
|
+
progress.start(1);
|
|
4264
|
+
progress.complete(1);
|
|
4265
|
+
}
|
|
4266
|
+
progress.start(2);
|
|
4267
|
+
progress.complete(2);
|
|
4268
|
+
progress.start(3);
|
|
4269
|
+
await updatePackageJson(projectRoot);
|
|
4270
|
+
progress.complete(3);
|
|
4271
|
+
progress.start(4);
|
|
4272
|
+
try {
|
|
4273
|
+
installDeps(projectRoot, packageManager);
|
|
4274
|
+
progress.complete(4);
|
|
4275
|
+
} catch (error) {
|
|
4276
|
+
progress.fail(4, error instanceof Error ? error.message : "Failed to install dependencies");
|
|
4277
|
+
progress.finish();
|
|
4278
|
+
throw error;
|
|
4279
|
+
}
|
|
4280
|
+
progress.start(5);
|
|
4281
|
+
try {
|
|
4282
|
+
initHusky(projectRoot, packageManager);
|
|
4283
|
+
progress.complete(5);
|
|
4284
|
+
} catch (error) {
|
|
4285
|
+
progress.fail(5, error instanceof Error ? error.message : "Failed to initialize husky");
|
|
4286
|
+
progress.finish();
|
|
4287
|
+
throw error;
|
|
4288
|
+
}
|
|
4289
|
+
progress.finish();
|
|
4290
|
+
logger.newline();
|
|
4291
|
+
logger.success(MESSAGES.COMMITLINT_SUCCESS);
|
|
4292
|
+
logger.dim(MESSAGES.COMMITLINT_SUCCESS_HINT);
|
|
4293
|
+
logger.newline();
|
|
4294
|
+
});
|
|
4295
|
+
}
|
|
4296
|
+
|
|
4297
|
+
// src/commands/list.ts
|
|
4298
|
+
init_esm_shims();
|
|
4299
|
+
async function fetchRegistryIndex() {
|
|
4300
|
+
const url = `${REGISTRY_BASE_URL}/__index.json`;
|
|
4301
|
+
let response;
|
|
4302
|
+
try {
|
|
4303
|
+
response = await fetch(url, { headers: { Accept: "application/json" } });
|
|
4304
|
+
} catch {
|
|
4305
|
+
throw new NetworkError();
|
|
4306
|
+
}
|
|
4307
|
+
if (!response.ok) {
|
|
4308
|
+
throw new NetworkError(`Failed to fetch registry index (HTTP ${response.status})`);
|
|
4309
|
+
}
|
|
4310
|
+
return response.json();
|
|
4311
|
+
}
|
|
4312
|
+
async function fetchNpmPackages() {
|
|
4313
|
+
const url = "https://registry.npmjs.org/-/v1/search?text=%40docyrus&size=100";
|
|
4314
|
+
let response;
|
|
4315
|
+
try {
|
|
4316
|
+
response = await fetch(url, { headers: { Accept: "application/json" } });
|
|
4317
|
+
} catch {
|
|
4318
|
+
throw new NetworkError();
|
|
4319
|
+
}
|
|
4320
|
+
if (!response.ok) {
|
|
4321
|
+
throw new NetworkError(`Failed to fetch npm packages (HTTP ${response.status})`);
|
|
4322
|
+
}
|
|
4323
|
+
const data = await response.json();
|
|
4324
|
+
return data.objects.map((o) => ({
|
|
4325
|
+
name: o.package.name,
|
|
4326
|
+
version: o.package.version,
|
|
4327
|
+
description: o.package.description,
|
|
4328
|
+
date: o.package.date
|
|
4329
|
+
}));
|
|
4330
|
+
}
|
|
4331
|
+
function groupByType(items) {
|
|
4332
|
+
const groups = {};
|
|
4333
|
+
for (const item of items) {
|
|
4334
|
+
const category = item.type.replace("registry:", "");
|
|
4335
|
+
const group = groups[category] ??= [];
|
|
4336
|
+
group.push(item);
|
|
4337
|
+
}
|
|
4338
|
+
return groups;
|
|
4339
|
+
}
|
|
4340
|
+
function printRegistryList(items) {
|
|
4341
|
+
const groups = groupByType(items);
|
|
4342
|
+
const categoryLabels = {
|
|
4343
|
+
ui: "Components",
|
|
4344
|
+
hook: "Hooks",
|
|
4345
|
+
lib: "Utilities"
|
|
4346
|
+
};
|
|
4347
|
+
logger.newline();
|
|
4348
|
+
logger.bold(MESSAGES.LIST_HEADER);
|
|
4349
|
+
logger.newline();
|
|
4350
|
+
for (const [type, group] of Object.entries(groups)) {
|
|
4351
|
+
const label = categoryLabels[type] || type;
|
|
4352
|
+
logger.info(chalk4.bold(label));
|
|
4353
|
+
for (const item of group) {
|
|
4354
|
+
const name = chalk4.cyan(item.name);
|
|
4355
|
+
const desc = item.description ? chalk4.dim(` \u2014 ${item.description}`) : "";
|
|
4356
|
+
logger.log(` ${name}${desc}`);
|
|
4357
|
+
}
|
|
4358
|
+
logger.newline();
|
|
4359
|
+
}
|
|
4360
|
+
logger.dim(MESSAGES.LIST_INSTALL_HINT);
|
|
4361
|
+
logger.newline();
|
|
4362
|
+
}
|
|
4363
|
+
function printNpmPackages(packages) {
|
|
4364
|
+
logger.newline();
|
|
4365
|
+
logger.bold(MESSAGES.LIST_NPM_HEADER);
|
|
4366
|
+
logger.newline();
|
|
4367
|
+
for (const pkg of packages) {
|
|
4368
|
+
const name = chalk4.cyan(pkg.name);
|
|
4369
|
+
const version = chalk4.dim(`@${pkg.version}`);
|
|
4370
|
+
const desc = pkg.description ? chalk4.dim(` \u2014 ${pkg.description}`) : "";
|
|
4371
|
+
logger.log(` ${name}${version}${desc}`);
|
|
4372
|
+
}
|
|
4373
|
+
logger.dim(`
|
|
4374
|
+
${MESSAGES.LIST_NPM_LINK}`);
|
|
4375
|
+
logger.newline();
|
|
4376
|
+
}
|
|
4377
|
+
function registerListCommand(program2) {
|
|
4378
|
+
program2.command("list").alias("ls").description("List available Docyrus UI components, hooks, and utilities").option("--packages", "List published @docyrus npm packages instead").addHelpText("after", `
|
|
4379
|
+
Examples:
|
|
4380
|
+
$ docyrus list List registry components
|
|
4381
|
+
$ docyrus ls Shorthand alias
|
|
4382
|
+
$ docyrus list --packages List published npm packages
|
|
4383
|
+
$ docyrus list --json Output as JSON
|
|
4384
|
+
`).action(async (options) => {
|
|
4385
|
+
if (options.packages) {
|
|
4386
|
+
const packages = await withSpinner(
|
|
4387
|
+
MESSAGES.LIST_FETCHING_NPM,
|
|
4388
|
+
fetchNpmPackages,
|
|
4389
|
+
{ successText: MESSAGES.LIST_NPM_SUCCESS }
|
|
4390
|
+
);
|
|
4391
|
+
if (output.isJson()) {
|
|
4392
|
+
output.success("ok", { packages });
|
|
4393
|
+
} else {
|
|
4394
|
+
printNpmPackages(packages);
|
|
4395
|
+
}
|
|
4396
|
+
} else {
|
|
4397
|
+
const items = await withSpinner(
|
|
4398
|
+
MESSAGES.LIST_FETCHING,
|
|
4399
|
+
fetchRegistryIndex
|
|
4400
|
+
);
|
|
4401
|
+
if (output.isJson()) {
|
|
4402
|
+
output.success("ok", { items });
|
|
4403
|
+
} else {
|
|
4404
|
+
printRegistryList(items);
|
|
4405
|
+
}
|
|
4406
|
+
}
|
|
4407
|
+
});
|
|
4408
|
+
}
|
|
4409
|
+
|
|
3682
4410
|
// src/commands/index.ts
|
|
3683
4411
|
function registerCommands(program2) {
|
|
3684
4412
|
registerLoginCommand(program2);
|
|
@@ -3686,6 +4414,8 @@ function registerCommands(program2) {
|
|
|
3686
4414
|
registerWhoamiCommand(program2);
|
|
3687
4415
|
registerCreateCommand(program2);
|
|
3688
4416
|
registerAddCommand(program2);
|
|
4417
|
+
registerListCommand(program2);
|
|
4418
|
+
registerCommitlintCommand(program2);
|
|
3689
4419
|
registerGenerateCommand(program2);
|
|
3690
4420
|
registerUpgradeCommand(program2);
|
|
3691
4421
|
registerCompletionCommand(program2);
|
|
@@ -3732,7 +4462,7 @@ async function checkForUpdates(packageName, currentVersion) {
|
|
|
3732
4462
|
|
|
3733
4463
|
// src/cli.ts
|
|
3734
4464
|
var program = new Command();
|
|
3735
|
-
program.name(CLI_NAME).description("Docyrus CLI - Authentication and project management tools").version(CLI_VERSION, "-v, --version", "Display version number").option("--json", "Output results in JSON format").hook("preAction", (thisCommand) => {
|
|
4465
|
+
program.name(CLI_NAME).description("Docyrus CLI - Authentication and project management tools").version(CLI_VERSION, "-v, --version", "Display version number").option("--json", "Output results in JSON format").configureHelp(getHelpConfig(configManager.get("helpTheme"))).hook("preAction", (thisCommand) => {
|
|
3736
4466
|
const opts = thisCommand.opts();
|
|
3737
4467
|
if (opts.json) {
|
|
3738
4468
|
output.setFormat("json");
|