@benbenwu/zcf 3.6.4 → 3.6.6
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 +31 -0
- package/dist/chunks/simple-config.mjs +117 -30
- package/dist/cli.mjs +0 -0
- package/package.json +52 -55
package/README.md
CHANGED
|
@@ -82,6 +82,37 @@ node bin/zcf.mjs i -s -T codex
|
|
|
82
82
|
|
|
83
83
|
Bare `npx @benbenwu/zcf` resolves the published npm package, so it will not automatically use your local repository changes.
|
|
84
84
|
|
|
85
|
+
## 📦 Release to npm
|
|
86
|
+
|
|
87
|
+
If you want `npx @benbenwu/zcf` to pick up your local changes, you must publish a new npm version. Republishing the same version is not allowed.
|
|
88
|
+
|
|
89
|
+
Recommended release flow for this repository:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# 1. Create a changeset and choose version bump type
|
|
93
|
+
pnpm changeset
|
|
94
|
+
|
|
95
|
+
# 2. Apply the version bump
|
|
96
|
+
pnpm changeset version
|
|
97
|
+
|
|
98
|
+
# 3. Run validation
|
|
99
|
+
pnpm lint
|
|
100
|
+
pnpm typecheck
|
|
101
|
+
pnpm test:run
|
|
102
|
+
pnpm build
|
|
103
|
+
|
|
104
|
+
# 4. Login to npm if needed
|
|
105
|
+
npm login
|
|
106
|
+
|
|
107
|
+
# 5. Publish using the repo release script
|
|
108
|
+
pnpm release
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Notes:
|
|
112
|
+
|
|
113
|
+
- `package.json` already sets `"publishConfig": { "access": "public" }`, so `pnpm release` / `changeset publish` will publish as a public package.
|
|
114
|
+
- `pnpm publish --access public` can still be used as a manual fallback after you run `pnpm changeset version` and `pnpm build`, but it is not the primary workflow in this repo.
|
|
115
|
+
|
|
85
116
|
More usage, options, and workflows: see documentation.
|
|
86
117
|
|
|
87
118
|
## 📖 Full Documentation
|
|
@@ -18,8 +18,8 @@ import { rm, mkdir, copyFile as copyFile$1 } from 'node:fs/promises';
|
|
|
18
18
|
import i18next from 'i18next';
|
|
19
19
|
import Backend from 'i18next-fs-backend';
|
|
20
20
|
|
|
21
|
-
const version = "3.6.
|
|
22
|
-
const homepage = "https://github.com/
|
|
21
|
+
const version = "3.6.6";
|
|
22
|
+
const homepage = "https://github.com/benbenlijie/zcf";
|
|
23
23
|
|
|
24
24
|
const i18n = i18next.createInstance();
|
|
25
25
|
const NAMESPACES = [
|
|
@@ -208,8 +208,8 @@ const MCP_SERVICE_CONFIGS = [
|
|
|
208
208
|
requiresApiKey: false,
|
|
209
209
|
config: {
|
|
210
210
|
type: "stdio",
|
|
211
|
-
command: "
|
|
212
|
-
args: ["
|
|
211
|
+
command: "serena",
|
|
212
|
+
args: ["start-mcp-server", "--context", "ide-assistant", "--enable-web-dashboard", "false"],
|
|
213
213
|
env: {}
|
|
214
214
|
}
|
|
215
215
|
}
|
|
@@ -3540,6 +3540,79 @@ async function selectMcpServices() {
|
|
|
3540
3540
|
return services;
|
|
3541
3541
|
}
|
|
3542
3542
|
|
|
3543
|
+
const UV_INSTALL_ARGS = ["tool", "install", "-p", "3.13", "serena-agent@latest", "--prerelease=allow"];
|
|
3544
|
+
function getExecutableCandidates(command) {
|
|
3545
|
+
const home = homedir();
|
|
3546
|
+
const extension = getPlatform() === "windows" ? ".exe" : "";
|
|
3547
|
+
return [
|
|
3548
|
+
join(home, ".local", "bin", `${command}${extension}`),
|
|
3549
|
+
join(home, ".cargo", "bin", `${command}${extension}`)
|
|
3550
|
+
];
|
|
3551
|
+
}
|
|
3552
|
+
async function resolveExecutablePath(command) {
|
|
3553
|
+
const discoveredPath = await findCommandPath(command);
|
|
3554
|
+
if (discoveredPath) {
|
|
3555
|
+
return discoveredPath;
|
|
3556
|
+
}
|
|
3557
|
+
for (const candidate of getExecutableCandidates(command)) {
|
|
3558
|
+
if (existsSync(candidate)) {
|
|
3559
|
+
return candidate;
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
return null;
|
|
3563
|
+
}
|
|
3564
|
+
async function installUv() {
|
|
3565
|
+
if (getPlatform() === "windows") {
|
|
3566
|
+
await exec("powershell", ["-ExecutionPolicy", "ByPass", "-c", "irm https://astral.sh/uv/install.ps1 | iex"]);
|
|
3567
|
+
return;
|
|
3568
|
+
}
|
|
3569
|
+
await exec("sh", ["-c", "curl -LsSf https://astral.sh/uv/install.sh | env UV_NO_MODIFY_PATH=1 sh"]);
|
|
3570
|
+
}
|
|
3571
|
+
async function ensureUvPath() {
|
|
3572
|
+
const existingPath = await resolveExecutablePath("uv");
|
|
3573
|
+
if (existingPath) {
|
|
3574
|
+
return existingPath;
|
|
3575
|
+
}
|
|
3576
|
+
await installUv();
|
|
3577
|
+
const installedPath = await resolveExecutablePath("uv");
|
|
3578
|
+
if (!installedPath) {
|
|
3579
|
+
throw new Error("uv installation completed but the uv executable was not found");
|
|
3580
|
+
}
|
|
3581
|
+
return installedPath;
|
|
3582
|
+
}
|
|
3583
|
+
async function installSerenaAgent(uvPath) {
|
|
3584
|
+
await exec(uvPath, UV_INSTALL_ARGS);
|
|
3585
|
+
}
|
|
3586
|
+
async function initializeSerena(serenaPath) {
|
|
3587
|
+
const serenaConfigFile = join(homedir(), ".serena", "serena_config.yml");
|
|
3588
|
+
if (existsSync(serenaConfigFile)) {
|
|
3589
|
+
return;
|
|
3590
|
+
}
|
|
3591
|
+
await exec(serenaPath, ["init"]);
|
|
3592
|
+
}
|
|
3593
|
+
async function ensureSerenaForCodex() {
|
|
3594
|
+
let serenaPath = await resolveExecutablePath("serena");
|
|
3595
|
+
if (!serenaPath) {
|
|
3596
|
+
const uvPath = await ensureUvPath();
|
|
3597
|
+
await installSerenaAgent(uvPath);
|
|
3598
|
+
serenaPath = await resolveExecutablePath("serena");
|
|
3599
|
+
}
|
|
3600
|
+
if (!serenaPath) {
|
|
3601
|
+
throw new Error("Serena installation completed but the serena executable was not found");
|
|
3602
|
+
}
|
|
3603
|
+
await initializeSerena(serenaPath);
|
|
3604
|
+
return serenaPath;
|
|
3605
|
+
}
|
|
3606
|
+
async function resolveCodexMcpCommandOverrides(serviceIds) {
|
|
3607
|
+
const normalizedIds = serviceIds.map((id) => id.toLowerCase());
|
|
3608
|
+
if (!normalizedIds.includes("serena")) {
|
|
3609
|
+
return {};
|
|
3610
|
+
}
|
|
3611
|
+
return {
|
|
3612
|
+
serena: await ensureSerenaForCodex()
|
|
3613
|
+
};
|
|
3614
|
+
}
|
|
3615
|
+
|
|
3543
3616
|
function applyCodexPlatformCommand(config) {
|
|
3544
3617
|
if (isWindows() && config.command) {
|
|
3545
3618
|
const mcpCmd = getMcpCommand(config.command);
|
|
@@ -3691,6 +3764,27 @@ const codexTomlUpdater = {
|
|
|
3691
3764
|
upsertCodexProvider: upsertCodexProvider
|
|
3692
3765
|
};
|
|
3693
3766
|
|
|
3767
|
+
function buildSerenaArgs() {
|
|
3768
|
+
return ["start-mcp-server", "--context=codex", "--project-from-cwd", "--enable-web-dashboard", "false"];
|
|
3769
|
+
}
|
|
3770
|
+
function applyCodexSpecificMcpOverrides(id, command, args, env) {
|
|
3771
|
+
const nextCommand = command;
|
|
3772
|
+
let nextArgs = args;
|
|
3773
|
+
let startupTimeoutSec = 30;
|
|
3774
|
+
if (id === "serena") {
|
|
3775
|
+
nextArgs = buildSerenaArgs();
|
|
3776
|
+
}
|
|
3777
|
+
if (id === "spec-workflow") {
|
|
3778
|
+
env.SPEC_WORKFLOW_HOME = join(homedir(), ".codex", "memories", "spec-workflow");
|
|
3779
|
+
startupTimeoutSec = 90;
|
|
3780
|
+
}
|
|
3781
|
+
return {
|
|
3782
|
+
command: nextCommand,
|
|
3783
|
+
args: nextArgs,
|
|
3784
|
+
env,
|
|
3785
|
+
startupTimeoutSec
|
|
3786
|
+
};
|
|
3787
|
+
}
|
|
3694
3788
|
async function configureCodexMcp(options) {
|
|
3695
3789
|
ensureI18nInitialized();
|
|
3696
3790
|
const { skipPrompt = false } = options ?? {};
|
|
@@ -3707,37 +3801,34 @@ async function configureCodexMcp(options) {
|
|
|
3707
3801
|
return;
|
|
3708
3802
|
}
|
|
3709
3803
|
const defaultServiceIds = Array.isArray(options?.mcpServices) ? options.mcpServices : MCP_SERVICE_CONFIGS.filter((service) => !service.requiresApiKey).map((service) => service.id);
|
|
3804
|
+
const commandOverrides2 = await resolveCodexMcpCommandOverrides(defaultServiceIds);
|
|
3710
3805
|
const existingServices2 = existingConfig?.mcpServices || [];
|
|
3711
3806
|
const selection2 = [];
|
|
3712
3807
|
for (const id of defaultServiceIds) {
|
|
3713
3808
|
const configInfo = MCP_SERVICE_CONFIGS.find((service) => service.id === id);
|
|
3714
3809
|
if (!configInfo)
|
|
3715
3810
|
continue;
|
|
3716
|
-
let command = configInfo.config.command || id;
|
|
3811
|
+
let command = commandOverrides2[id.toLowerCase()] || configInfo.config.command || id;
|
|
3717
3812
|
let args = (configInfo.config.args || []).map((arg) => String(arg));
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
else
|
|
3723
|
-
args.push("--context", "codex");
|
|
3724
|
-
}
|
|
3813
|
+
const env = { ...configInfo.config.env || {} };
|
|
3814
|
+
const serviceConfigOverride = applyCodexSpecificMcpOverrides(id, command, args, env);
|
|
3815
|
+
command = serviceConfigOverride.command;
|
|
3816
|
+
args = serviceConfigOverride.args;
|
|
3725
3817
|
const serviceConfig = { id: id.toLowerCase(), command, args };
|
|
3726
3818
|
applyCodexPlatformCommand(serviceConfig);
|
|
3727
3819
|
command = serviceConfig.command;
|
|
3728
3820
|
args = serviceConfig.args || [];
|
|
3729
|
-
const env = { ...configInfo.config.env || {} };
|
|
3730
3821
|
if (isWindows()) {
|
|
3731
3822
|
const systemRoot = getSystemRoot();
|
|
3732
3823
|
if (systemRoot)
|
|
3733
|
-
env.SYSTEMROOT = systemRoot;
|
|
3824
|
+
serviceConfigOverride.env.SYSTEMROOT = systemRoot;
|
|
3734
3825
|
}
|
|
3735
3826
|
selection2.push({
|
|
3736
3827
|
id: id.toLowerCase(),
|
|
3737
3828
|
command,
|
|
3738
3829
|
args,
|
|
3739
|
-
env: Object.keys(env).length > 0 ? env : void 0,
|
|
3740
|
-
startup_timeout_sec:
|
|
3830
|
+
env: Object.keys(serviceConfigOverride.env).length > 0 ? serviceConfigOverride.env : void 0,
|
|
3831
|
+
startup_timeout_sec: serviceConfigOverride.startupTimeoutSec
|
|
3741
3832
|
});
|
|
3742
3833
|
}
|
|
3743
3834
|
const mergedMap2 = /* @__PURE__ */ new Map();
|
|
@@ -3769,6 +3860,7 @@ async function configureCodexMcp(options) {
|
|
|
3769
3860
|
if (!selectedIds)
|
|
3770
3861
|
return;
|
|
3771
3862
|
const servicesMeta = await getMcpServices();
|
|
3863
|
+
const commandOverrides = await resolveCodexMcpCommandOverrides(selectedIds);
|
|
3772
3864
|
const selection = [];
|
|
3773
3865
|
const existingServices = existingConfig?.mcpServices || [];
|
|
3774
3866
|
if (selectedIds.length === 0) {
|
|
@@ -3797,25 +3889,20 @@ async function configureCodexMcp(options) {
|
|
|
3797
3889
|
if (!configInfo)
|
|
3798
3890
|
continue;
|
|
3799
3891
|
const serviceMeta = servicesMeta.find((service) => service.id === id);
|
|
3800
|
-
let command = configInfo.config.command || id;
|
|
3892
|
+
let command = commandOverrides[id.toLowerCase()] || configInfo.config.command || id;
|
|
3801
3893
|
let args = (configInfo.config.args || []).map((arg) => String(arg));
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
} else {
|
|
3807
|
-
args.push("--context", "codex");
|
|
3808
|
-
}
|
|
3809
|
-
}
|
|
3894
|
+
const env = { ...configInfo.config.env || {} };
|
|
3895
|
+
const serviceConfigOverride = applyCodexSpecificMcpOverrides(id, command, args, env);
|
|
3896
|
+
command = serviceConfigOverride.command;
|
|
3897
|
+
args = serviceConfigOverride.args;
|
|
3810
3898
|
const serviceConfig = { id: id.toLowerCase(), command, args };
|
|
3811
3899
|
applyCodexPlatformCommand(serviceConfig);
|
|
3812
3900
|
command = serviceConfig.command;
|
|
3813
3901
|
args = serviceConfig.args || [];
|
|
3814
|
-
const env = { ...configInfo.config.env || {} };
|
|
3815
3902
|
if (isWindows()) {
|
|
3816
3903
|
const systemRoot = getSystemRoot();
|
|
3817
3904
|
if (systemRoot)
|
|
3818
|
-
env.SYSTEMROOT = systemRoot;
|
|
3905
|
+
serviceConfigOverride.env.SYSTEMROOT = systemRoot;
|
|
3819
3906
|
}
|
|
3820
3907
|
if (configInfo.requiresApiKey && configInfo.apiKeyEnvVar) {
|
|
3821
3908
|
const promptMessage = serviceMeta?.apiKeyPrompt || i18n.t("mcp:apiKeyPrompt");
|
|
@@ -3827,14 +3914,14 @@ async function configureCodexMcp(options) {
|
|
|
3827
3914
|
}]);
|
|
3828
3915
|
if (!apiKey)
|
|
3829
3916
|
continue;
|
|
3830
|
-
env[configInfo.apiKeyEnvVar] = apiKey;
|
|
3917
|
+
serviceConfigOverride.env[configInfo.apiKeyEnvVar] = apiKey;
|
|
3831
3918
|
}
|
|
3832
3919
|
selection.push({
|
|
3833
3920
|
id: id.toLowerCase(),
|
|
3834
3921
|
command: serviceConfig.command,
|
|
3835
3922
|
args: serviceConfig.args,
|
|
3836
|
-
env: Object.keys(env).length > 0 ? env : void 0,
|
|
3837
|
-
startup_timeout_sec:
|
|
3923
|
+
env: Object.keys(serviceConfigOverride.env).length > 0 ? serviceConfigOverride.env : void 0,
|
|
3924
|
+
startup_timeout_sec: serviceConfigOverride.startupTimeoutSec
|
|
3838
3925
|
});
|
|
3839
3926
|
}
|
|
3840
3927
|
const mergedMap = /* @__PURE__ */ new Map();
|
package/dist/cli.mjs
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@benbenwu/zcf",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.6.
|
|
5
|
-
"packageManager": "pnpm@10.17.1",
|
|
4
|
+
"version": "3.6.6",
|
|
6
5
|
"description": "Zero-Config Code Flow - One-click configuration tool for Code Cli",
|
|
7
6
|
"author": {
|
|
8
|
-
"name": "
|
|
9
|
-
"email": "
|
|
10
|
-
"url": "https://github.com/
|
|
7
|
+
"name": "Wu Yubin",
|
|
8
|
+
"email": "benbenwyb@gmail.com",
|
|
9
|
+
"url": "https://github.com/benbenlijie"
|
|
11
10
|
},
|
|
12
11
|
"license": "MIT",
|
|
13
12
|
"publishConfig": {
|
|
14
13
|
"access": "public"
|
|
15
14
|
},
|
|
16
|
-
"homepage": "https://github.com/
|
|
15
|
+
"homepage": "https://github.com/benbenlijie/zcf",
|
|
17
16
|
"repository": {
|
|
18
17
|
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/
|
|
18
|
+
"url": "git+https://github.com/benbenlijie/zcf.git"
|
|
20
19
|
},
|
|
21
|
-
"bugs": "https://github.com/
|
|
20
|
+
"bugs": "https://github.com/benbenlijie/zcf/issues",
|
|
22
21
|
"keywords": [
|
|
23
22
|
"claude",
|
|
24
23
|
"claude-code",
|
|
@@ -46,12 +45,55 @@
|
|
|
46
45
|
"dist",
|
|
47
46
|
"templates"
|
|
48
47
|
],
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@rainbowatcher/toml-edit-js": "^0.6.4",
|
|
50
|
+
"@types/semver": "^7.7.1",
|
|
51
|
+
"ansis": "^4.1.0",
|
|
52
|
+
"cac": "^6.7.14",
|
|
53
|
+
"dayjs": "^1.11.18",
|
|
54
|
+
"find-up-simple": "^1.0.1",
|
|
55
|
+
"fs-extra": "^11.3.2",
|
|
56
|
+
"i18next": "^25.5.2",
|
|
57
|
+
"i18next-fs-backend": "^2.6.0",
|
|
58
|
+
"inquirer": "^12.9.6",
|
|
59
|
+
"inquirer-toggle": "^1.0.1",
|
|
60
|
+
"ora": "^9.0.0",
|
|
61
|
+
"pathe": "^2.0.3",
|
|
62
|
+
"semver": "^7.7.2",
|
|
63
|
+
"tinyexec": "^1.0.1",
|
|
64
|
+
"trash": "^10.0.0"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@antfu/eslint-config": "^5.4.1",
|
|
68
|
+
"@changesets/cli": "^2.30.0",
|
|
69
|
+
"@commitlint/cli": "^19.8.1",
|
|
70
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
71
|
+
"@commitlint/types": "^19.8.1",
|
|
72
|
+
"@types/fs-extra": "^11.0.4",
|
|
73
|
+
"@types/inquirer": "^9.0.9",
|
|
74
|
+
"@types/node": "^22.18.6",
|
|
75
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
76
|
+
"@vitest/ui": "^3.2.4",
|
|
77
|
+
"eslint": "^9.36.0",
|
|
78
|
+
"eslint-plugin-format": "^1.0.2",
|
|
79
|
+
"glob": "^11.0.3",
|
|
80
|
+
"husky": "^9.1.7",
|
|
81
|
+
"lint-staged": "^16.2.0",
|
|
82
|
+
"tsx": "^4.20.5",
|
|
83
|
+
"typescript": "^5.9.2",
|
|
84
|
+
"unbuild": "^3.6.1",
|
|
85
|
+
"vitest": "^3.2.4"
|
|
86
|
+
},
|
|
87
|
+
"lint-staged": {
|
|
88
|
+
"*": [
|
|
89
|
+
"pnpm lint"
|
|
90
|
+
]
|
|
91
|
+
},
|
|
49
92
|
"scripts": {
|
|
50
93
|
"dev": "tsx ./src/cli.ts",
|
|
51
94
|
"build": "unbuild",
|
|
52
95
|
"start": "node bin/zcf.mjs",
|
|
53
96
|
"typecheck": "tsc --noEmit",
|
|
54
|
-
"prepublishOnly": "pnpm build",
|
|
55
97
|
"lint": "eslint",
|
|
56
98
|
"lint:fix": "eslint --fix",
|
|
57
99
|
"test": "vitest",
|
|
@@ -63,55 +105,10 @@
|
|
|
63
105
|
"version": "changeset version",
|
|
64
106
|
"update:deps": "pnpx taze major -r -w",
|
|
65
107
|
"release": "pnpm build && changeset publish",
|
|
66
|
-
"prepare": "husky",
|
|
67
108
|
"commitlint": "commitlint",
|
|
68
109
|
"commitlint:check": "commitlint --from HEAD~1 --to HEAD --verbose",
|
|
69
110
|
"docs:dev": "pnpm -F @zcf/docs dev",
|
|
70
111
|
"docs:build": "pnpm -F @zcf/docs build",
|
|
71
112
|
"docs:preview": "pnpm -F @zcf/docs preview"
|
|
72
|
-
},
|
|
73
|
-
"dependencies": {
|
|
74
|
-
"@rainbowatcher/toml-edit-js": "catalog:runtime",
|
|
75
|
-
"@types/semver": "catalog:types",
|
|
76
|
-
"ansis": "catalog:cli",
|
|
77
|
-
"cac": "catalog:cli",
|
|
78
|
-
"dayjs": "catalog:runtime",
|
|
79
|
-
"find-up-simple": "catalog:runtime",
|
|
80
|
-
"fs-extra": "catalog:runtime",
|
|
81
|
-
"i18next": "catalog:runtime",
|
|
82
|
-
"i18next-fs-backend": "catalog:runtime",
|
|
83
|
-
"inquirer": "catalog:cli",
|
|
84
|
-
"inquirer-toggle": "catalog:cli",
|
|
85
|
-
"ora": "catalog:cli",
|
|
86
|
-
"pathe": "catalog:runtime",
|
|
87
|
-
"semver": "catalog:runtime",
|
|
88
|
-
"tinyexec": "catalog:runtime",
|
|
89
|
-
"trash": "catalog:runtime"
|
|
90
|
-
},
|
|
91
|
-
"devDependencies": {
|
|
92
|
-
"@antfu/eslint-config": "catalog:build",
|
|
93
|
-
"@changesets/cli": "catalog:tooling",
|
|
94
|
-
"@commitlint/cli": "catalog:tooling",
|
|
95
|
-
"@commitlint/config-conventional": "catalog:tooling",
|
|
96
|
-
"@commitlint/types": "catalog:tooling",
|
|
97
|
-
"@types/fs-extra": "catalog:types",
|
|
98
|
-
"@types/inquirer": "catalog:types",
|
|
99
|
-
"@types/node": "catalog:types",
|
|
100
|
-
"@vitest/coverage-v8": "catalog:testing",
|
|
101
|
-
"@vitest/ui": "catalog:testing",
|
|
102
|
-
"eslint": "catalog:build",
|
|
103
|
-
"eslint-plugin-format": "catalog:build",
|
|
104
|
-
"glob": "catalog:testing",
|
|
105
|
-
"husky": "catalog:tooling",
|
|
106
|
-
"lint-staged": "catalog:tooling",
|
|
107
|
-
"tsx": "catalog:build",
|
|
108
|
-
"typescript": "catalog:build",
|
|
109
|
-
"unbuild": "catalog:build",
|
|
110
|
-
"vitest": "catalog:testing"
|
|
111
|
-
},
|
|
112
|
-
"lint-staged": {
|
|
113
|
-
"*": [
|
|
114
|
-
"pnpm lint"
|
|
115
|
-
]
|
|
116
113
|
}
|
|
117
|
-
}
|
|
114
|
+
}
|