@gowelle/stint-agent 1.0.3 → 1.0.5
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
|
@@ -62,11 +62,13 @@ stint daemon status
|
|
|
62
62
|
| `stint logout` | Remove stored credentials |
|
|
63
63
|
| `stint whoami` | Show current user and machine information |
|
|
64
64
|
|
|
65
|
-
### Daemon
|
|
65
|
+
### Daemon Lifecycle
|
|
66
66
|
|
|
67
67
|
| Command | Description |
|
|
68
68
|
|---------|-------------|
|
|
69
|
-
| `stint
|
|
69
|
+
| `stint install` | Register daemon to run on system startup (Login required) |
|
|
70
|
+
| `stint uninstall` | Remove daemon from system startup |
|
|
71
|
+
| `stint daemon start` | Start background daemon manually |
|
|
70
72
|
| `stint daemon stop` | Stop daemon gracefully |
|
|
71
73
|
| `stint daemon status` | Check if daemon is running |
|
|
72
74
|
| `stint daemon logs [--lines N]` | View daemon logs (default: 50 lines) |
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
apiService,
|
|
3
3
|
config,
|
|
4
4
|
logger
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-BSBIB3MX.js";
|
|
6
6
|
|
|
7
7
|
// src/utils/process.ts
|
|
8
8
|
import fs from "fs";
|
|
@@ -121,6 +121,20 @@ var GitServiceImpl = class {
|
|
|
121
121
|
const branches = branchSummary.all;
|
|
122
122
|
const remotes = await git.getRemotes(true);
|
|
123
123
|
const remoteUrl = remotes.length > 0 ? remotes[0].refs.fetch : null;
|
|
124
|
+
let defaultBranch = currentBranch;
|
|
125
|
+
try {
|
|
126
|
+
const result = await git.raw(["symbolic-ref", "refs/remotes/origin/HEAD"]);
|
|
127
|
+
const match = result.trim().match(/refs\/remotes\/origin\/(.+)/);
|
|
128
|
+
if (match) {
|
|
129
|
+
defaultBranch = match[1];
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
if (branches.includes("main")) {
|
|
133
|
+
defaultBranch = "main";
|
|
134
|
+
} else if (branches.includes("master")) {
|
|
135
|
+
defaultBranch = "master";
|
|
136
|
+
}
|
|
137
|
+
}
|
|
124
138
|
const status = await this.getStatus(path3);
|
|
125
139
|
const log = await git.log({ maxCount: 1 });
|
|
126
140
|
const lastCommit = log.latest;
|
|
@@ -128,7 +142,9 @@ var GitServiceImpl = class {
|
|
|
128
142
|
throw new Error("No commits found in repository");
|
|
129
143
|
}
|
|
130
144
|
return {
|
|
145
|
+
repoPath: path3,
|
|
131
146
|
currentBranch,
|
|
147
|
+
defaultBranch,
|
|
132
148
|
branches,
|
|
133
149
|
remoteUrl,
|
|
134
150
|
status,
|
|
@@ -254,7 +254,7 @@ var AuthServiceImpl = class {
|
|
|
254
254
|
return null;
|
|
255
255
|
}
|
|
256
256
|
try {
|
|
257
|
-
const { apiService: apiService2 } = await import("./api-
|
|
257
|
+
const { apiService: apiService2 } = await import("./api-OUZE76VQ.js");
|
|
258
258
|
const user = await apiService2.getCurrentUser();
|
|
259
259
|
logger.info("auth", `Token validated for user: ${user.email}`);
|
|
260
260
|
return user;
|
|
@@ -274,7 +274,7 @@ var AuthServiceImpl = class {
|
|
|
274
274
|
var authService = new AuthServiceImpl();
|
|
275
275
|
|
|
276
276
|
// src/services/api.ts
|
|
277
|
-
var AGENT_VERSION = "1.0.
|
|
277
|
+
var AGENT_VERSION = "1.0.5";
|
|
278
278
|
var ApiServiceImpl = class {
|
|
279
279
|
sessionId = null;
|
|
280
280
|
async getHeaders() {
|
|
@@ -432,9 +432,15 @@ var ApiServiceImpl = class {
|
|
|
432
432
|
async syncProject(projectId, data) {
|
|
433
433
|
logger.info("api", `Syncing project ${projectId}`);
|
|
434
434
|
await this.withRetry(async () => {
|
|
435
|
+
const payload = {
|
|
436
|
+
repo_path: data.repoPath,
|
|
437
|
+
remote_url: data.remoteUrl,
|
|
438
|
+
default_branch: data.defaultBranch,
|
|
439
|
+
current_branch: data.currentBranch
|
|
440
|
+
};
|
|
435
441
|
await this.request(`/api/agent/projects/${projectId}/sync`, {
|
|
436
442
|
method: "POST",
|
|
437
|
-
body: JSON.stringify(
|
|
443
|
+
body: JSON.stringify(payload)
|
|
438
444
|
});
|
|
439
445
|
logger.success("api", `Project ${projectId} synced`);
|
|
440
446
|
}, "Sync project");
|
package/dist/daemon/runner.js
CHANGED
|
@@ -5,13 +5,13 @@ import {
|
|
|
5
5
|
projectService,
|
|
6
6
|
removePidFile,
|
|
7
7
|
writePidFile
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-5PC3XTZ7.js";
|
|
9
9
|
import {
|
|
10
10
|
apiService,
|
|
11
11
|
authService,
|
|
12
12
|
config,
|
|
13
13
|
logger
|
|
14
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-BSBIB3MX.js";
|
|
15
15
|
|
|
16
16
|
// src/daemon/runner.ts
|
|
17
17
|
import "dotenv/config";
|
|
@@ -457,6 +457,10 @@ async function startDaemon() {
|
|
|
457
457
|
try {
|
|
458
458
|
const user = await authService.validateToken();
|
|
459
459
|
if (!user) {
|
|
460
|
+
notify({
|
|
461
|
+
title: "Stint Agent",
|
|
462
|
+
message: 'Authentication expired. Please run "stint login" to reconnect.'
|
|
463
|
+
});
|
|
460
464
|
throw new Error('Not authenticated. Please run "stint login" first.');
|
|
461
465
|
}
|
|
462
466
|
logger.info("daemon", `Authenticated as ${user.email}`);
|
package/dist/index.js
CHANGED
|
@@ -8,18 +8,18 @@ import {
|
|
|
8
8
|
projectService,
|
|
9
9
|
spawnDetached,
|
|
10
10
|
validatePidFile
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-5PC3XTZ7.js";
|
|
12
12
|
import {
|
|
13
13
|
apiService,
|
|
14
14
|
authService,
|
|
15
15
|
config,
|
|
16
16
|
logger
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-BSBIB3MX.js";
|
|
18
18
|
|
|
19
19
|
// src/index.ts
|
|
20
20
|
import "dotenv/config";
|
|
21
21
|
import { Command } from "commander";
|
|
22
|
-
import
|
|
22
|
+
import chalk11 from "chalk";
|
|
23
23
|
|
|
24
24
|
// src/commands/login.ts
|
|
25
25
|
import open from "open";
|
|
@@ -1061,19 +1061,225 @@ function getTimeAgo(date) {
|
|
|
1061
1061
|
return date.toLocaleDateString();
|
|
1062
1062
|
}
|
|
1063
1063
|
|
|
1064
|
+
// src/commands/install.ts
|
|
1065
|
+
import ora10 from "ora";
|
|
1066
|
+
import chalk10 from "chalk";
|
|
1067
|
+
import fs2 from "fs";
|
|
1068
|
+
import path4 from "path";
|
|
1069
|
+
import os3 from "os";
|
|
1070
|
+
import { exec } from "child_process";
|
|
1071
|
+
import { promisify } from "util";
|
|
1072
|
+
var execAsync = promisify(exec);
|
|
1073
|
+
var WINDOWS_TASK_NAME = "StintAgentDaemon";
|
|
1074
|
+
var MAC_PLIST_NAME = "codes.stint.agent.plist";
|
|
1075
|
+
var SYSTEMD_SERVICE_NAME = "stint-agent.service";
|
|
1076
|
+
function getDaemonCommand() {
|
|
1077
|
+
const scriptPath = process.argv[1];
|
|
1078
|
+
return `"${process.execPath}" "${scriptPath}" daemon start`;
|
|
1079
|
+
}
|
|
1080
|
+
async function installWindows() {
|
|
1081
|
+
const command = getDaemonCommand();
|
|
1082
|
+
const escapedCommand = command.replace(/"/g, '\\"');
|
|
1083
|
+
try {
|
|
1084
|
+
await execAsync(`schtasks /Create /SC ONLOGON /TN "${WINDOWS_TASK_NAME}" /TR "${escapedCommand}" /F`);
|
|
1085
|
+
} catch (error) {
|
|
1086
|
+
if (error.message.includes("Access is denied")) {
|
|
1087
|
+
throw new Error("Access denied. Please run this command as Administrator (Right-click Terminal > Run as administrator).");
|
|
1088
|
+
}
|
|
1089
|
+
throw error;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
async function uninstallWindows() {
|
|
1093
|
+
await execAsync(`schtasks /Delete /TN "${WINDOWS_TASK_NAME}" /F`);
|
|
1094
|
+
}
|
|
1095
|
+
function getMacPlistContent() {
|
|
1096
|
+
const scriptPath = process.argv[1];
|
|
1097
|
+
const logPath = path4.join(os3.homedir(), ".config", "stint", "logs", "launchd.log");
|
|
1098
|
+
const errorPath = path4.join(os3.homedir(), ".config", "stint", "logs", "launchd.error.log");
|
|
1099
|
+
const logDir = path4.dirname(logPath);
|
|
1100
|
+
if (!fs2.existsSync(logDir)) {
|
|
1101
|
+
fs2.mkdirSync(logDir, { recursive: true });
|
|
1102
|
+
}
|
|
1103
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1104
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
1105
|
+
<plist version="1.0">
|
|
1106
|
+
<dict>
|
|
1107
|
+
<key>Label</key>
|
|
1108
|
+
<string>codes.stint.agent</string>
|
|
1109
|
+
<key>ProgramArguments</key>
|
|
1110
|
+
<array>
|
|
1111
|
+
<string>${process.execPath}</string>
|
|
1112
|
+
<string>${scriptPath}</string>
|
|
1113
|
+
<string>daemon</string>
|
|
1114
|
+
<string>start</string>
|
|
1115
|
+
</array>
|
|
1116
|
+
<key>RunAtLoad</key>
|
|
1117
|
+
<true/>
|
|
1118
|
+
<key>StandardOutPath</key>
|
|
1119
|
+
<string>${logPath}</string>
|
|
1120
|
+
<key>StandardErrorPath</key>
|
|
1121
|
+
<string>${errorPath}</string>
|
|
1122
|
+
<key>EnvironmentVariables</key>
|
|
1123
|
+
<dict>
|
|
1124
|
+
<key>PATH</key>
|
|
1125
|
+
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
1126
|
+
</dict>
|
|
1127
|
+
</dict>
|
|
1128
|
+
</plist>`;
|
|
1129
|
+
}
|
|
1130
|
+
async function installMac() {
|
|
1131
|
+
const plistContent = getMacPlistContent();
|
|
1132
|
+
const launchAgentsDir = path4.join(os3.homedir(), "Library", "LaunchAgents");
|
|
1133
|
+
const plistPath = path4.join(launchAgentsDir, MAC_PLIST_NAME);
|
|
1134
|
+
if (!fs2.existsSync(launchAgentsDir)) {
|
|
1135
|
+
fs2.mkdirSync(launchAgentsDir, { recursive: true });
|
|
1136
|
+
}
|
|
1137
|
+
fs2.writeFileSync(plistPath, plistContent);
|
|
1138
|
+
try {
|
|
1139
|
+
await execAsync(`launchctl unload "${plistPath}"`);
|
|
1140
|
+
} catch {
|
|
1141
|
+
}
|
|
1142
|
+
await execAsync(`launchctl load "${plistPath}"`);
|
|
1143
|
+
}
|
|
1144
|
+
async function uninstallMac() {
|
|
1145
|
+
const launchAgentsDir = path4.join(os3.homedir(), "Library", "LaunchAgents");
|
|
1146
|
+
const plistPath = path4.join(launchAgentsDir, MAC_PLIST_NAME);
|
|
1147
|
+
if (fs2.existsSync(plistPath)) {
|
|
1148
|
+
try {
|
|
1149
|
+
await execAsync(`launchctl unload "${plistPath}"`);
|
|
1150
|
+
} catch {
|
|
1151
|
+
}
|
|
1152
|
+
fs2.unlinkSync(plistPath);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
function getSystemdServiceContent() {
|
|
1156
|
+
const scriptPath = process.argv[1];
|
|
1157
|
+
return `[Unit]
|
|
1158
|
+
Description=Stint Agent (Project Assistant)
|
|
1159
|
+
After=network.target
|
|
1160
|
+
|
|
1161
|
+
[Service]
|
|
1162
|
+
Type=forking
|
|
1163
|
+
ExecStart=${process.execPath} "${scriptPath}" daemon start
|
|
1164
|
+
Restart=on-failure
|
|
1165
|
+
RestartSec=5
|
|
1166
|
+
StandardOutput=journal
|
|
1167
|
+
StandardError=journal
|
|
1168
|
+
|
|
1169
|
+
[Install]
|
|
1170
|
+
WantedBy=default.target`;
|
|
1171
|
+
}
|
|
1172
|
+
async function installLinux() {
|
|
1173
|
+
const systemdDir = path4.join(os3.homedir(), ".config", "systemd", "user");
|
|
1174
|
+
const servicePath = path4.join(systemdDir, SYSTEMD_SERVICE_NAME);
|
|
1175
|
+
if (!fs2.existsSync(systemdDir)) {
|
|
1176
|
+
fs2.mkdirSync(systemdDir, { recursive: true });
|
|
1177
|
+
}
|
|
1178
|
+
const serviceContent = getSystemdServiceContent();
|
|
1179
|
+
fs2.writeFileSync(servicePath, serviceContent);
|
|
1180
|
+
await execAsync("systemctl --user daemon-reload");
|
|
1181
|
+
await execAsync(`systemctl --user enable ${SYSTEMD_SERVICE_NAME}`);
|
|
1182
|
+
await execAsync(`systemctl --user start ${SYSTEMD_SERVICE_NAME}`);
|
|
1183
|
+
}
|
|
1184
|
+
async function uninstallLinux() {
|
|
1185
|
+
const systemdDir = path4.join(os3.homedir(), ".config", "systemd", "user");
|
|
1186
|
+
const servicePath = path4.join(systemdDir, SYSTEMD_SERVICE_NAME);
|
|
1187
|
+
try {
|
|
1188
|
+
await execAsync(`systemctl --user stop ${SYSTEMD_SERVICE_NAME}`);
|
|
1189
|
+
await execAsync(`systemctl --user disable ${SYSTEMD_SERVICE_NAME}`);
|
|
1190
|
+
} catch {
|
|
1191
|
+
}
|
|
1192
|
+
if (fs2.existsSync(servicePath)) {
|
|
1193
|
+
fs2.unlinkSync(servicePath);
|
|
1194
|
+
await execAsync("systemctl --user daemon-reload");
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
function registerInstallCommand(program2) {
|
|
1198
|
+
program2.command("install").description("Install stint agent to run on system startup").action(async () => {
|
|
1199
|
+
const spinner = ora10("Checking authentication...").start();
|
|
1200
|
+
try {
|
|
1201
|
+
const user = await authService.validateToken();
|
|
1202
|
+
if (!user) {
|
|
1203
|
+
spinner.fail("Not authenticated");
|
|
1204
|
+
console.log(chalk10.red("\n\u2716 You must be logged in to install the background agent on startup."));
|
|
1205
|
+
console.log(chalk10.gray('Run "stint login" first.\n'));
|
|
1206
|
+
process.exit(1);
|
|
1207
|
+
}
|
|
1208
|
+
spinner.text = "Installing startup agent...";
|
|
1209
|
+
const platform = os3.platform();
|
|
1210
|
+
if (platform === "win32") {
|
|
1211
|
+
await installWindows();
|
|
1212
|
+
} else if (platform === "darwin") {
|
|
1213
|
+
await installMac();
|
|
1214
|
+
} else if (platform === "linux") {
|
|
1215
|
+
await installLinux();
|
|
1216
|
+
} else {
|
|
1217
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
1218
|
+
}
|
|
1219
|
+
spinner.succeed("Installed successfully!");
|
|
1220
|
+
console.log(chalk10.green(`
|
|
1221
|
+
\u2713 Stint agent configured to start on login`));
|
|
1222
|
+
if (platform === "win32") {
|
|
1223
|
+
console.log(chalk10.gray(`Registered Task Scheduler task: ${WINDOWS_TASK_NAME}`));
|
|
1224
|
+
} else if (platform === "darwin") {
|
|
1225
|
+
console.log(chalk10.gray(`Created LaunchAgent: ~/Library/LaunchAgents/${MAC_PLIST_NAME}`));
|
|
1226
|
+
} else if (platform === "linux") {
|
|
1227
|
+
console.log(chalk10.gray(`Created systemd user service: ${SYSTEMD_SERVICE_NAME}`));
|
|
1228
|
+
}
|
|
1229
|
+
console.log();
|
|
1230
|
+
logger.success("install", `Agent installed on startup for ${platform}`);
|
|
1231
|
+
} catch (error) {
|
|
1232
|
+
spinner.fail("Installation failed");
|
|
1233
|
+
logger.error("install", "Install command failed", error);
|
|
1234
|
+
console.error(chalk10.red(`
|
|
1235
|
+
\u2716 Error: ${error.message}
|
|
1236
|
+
`));
|
|
1237
|
+
process.exit(1);
|
|
1238
|
+
}
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
function registerUninstallCommand(program2) {
|
|
1242
|
+
program2.command("uninstall").description("Remove stint agent from system startup").action(async () => {
|
|
1243
|
+
const spinner = ora10("Removing startup agent...").start();
|
|
1244
|
+
try {
|
|
1245
|
+
const platform = os3.platform();
|
|
1246
|
+
if (platform === "win32") {
|
|
1247
|
+
await uninstallWindows();
|
|
1248
|
+
} else if (platform === "darwin") {
|
|
1249
|
+
await uninstallMac();
|
|
1250
|
+
} else if (platform === "linux") {
|
|
1251
|
+
await uninstallLinux();
|
|
1252
|
+
} else {
|
|
1253
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
1254
|
+
}
|
|
1255
|
+
spinner.succeed("Uninstalled successfully");
|
|
1256
|
+
console.log(chalk10.gray("\nStint agent removed from system startup.\n"));
|
|
1257
|
+
logger.success("install", `Agent uninstalled from startup for ${platform}`);
|
|
1258
|
+
} catch (error) {
|
|
1259
|
+
spinner.fail("Uninstall failed");
|
|
1260
|
+
logger.error("install", "Uninstall command failed", error);
|
|
1261
|
+
console.error(chalk10.red(`
|
|
1262
|
+
\u2716 Error: ${error.message}
|
|
1263
|
+
`));
|
|
1264
|
+
process.exit(1);
|
|
1265
|
+
}
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1064
1269
|
// src/index.ts
|
|
1065
|
-
var AGENT_VERSION = "1.0.
|
|
1270
|
+
var AGENT_VERSION = "1.0.5";
|
|
1066
1271
|
var program = new Command();
|
|
1067
1272
|
program.name("stint").description("Stint Agent - Local daemon for Stint Project Assistant").version(AGENT_VERSION, "-V, --version", "output the current version").addHelpText("after", `
|
|
1068
|
-
${
|
|
1069
|
-
${
|
|
1070
|
-
${
|
|
1071
|
-
${
|
|
1072
|
-
${
|
|
1073
|
-
${
|
|
1273
|
+
${chalk11.bold("Examples:")}
|
|
1274
|
+
${chalk11.cyan("$")} stint login ${chalk11.gray("# Authenticate with Stint")}
|
|
1275
|
+
${chalk11.cyan("$")} stint install ${chalk11.gray("# Install agent to run on startup")}
|
|
1276
|
+
${chalk11.cyan("$")} stint link ${chalk11.gray("# Link current directory to a project")}
|
|
1277
|
+
${chalk11.cyan("$")} stint daemon start ${chalk11.gray("# Start background daemon")}
|
|
1278
|
+
${chalk11.cyan("$")} stint status ${chalk11.gray("# Check status")}
|
|
1279
|
+
${chalk11.cyan("$")} stint commits ${chalk11.gray("# List pending commits")}
|
|
1074
1280
|
|
|
1075
|
-
${
|
|
1076
|
-
For more information, visit: ${
|
|
1281
|
+
${chalk11.bold("Documentation:")}
|
|
1282
|
+
For more information, visit: ${chalk11.blue("https://stint.codes/docs")}
|
|
1077
1283
|
`);
|
|
1078
1284
|
registerLoginCommand(program);
|
|
1079
1285
|
registerLogoutCommand(program);
|
|
@@ -1084,6 +1290,8 @@ registerStatusCommand(program);
|
|
|
1084
1290
|
registerSyncCommand(program);
|
|
1085
1291
|
registerDaemonCommands(program);
|
|
1086
1292
|
registerCommitCommands(program);
|
|
1293
|
+
registerInstallCommand(program);
|
|
1294
|
+
registerUninstallCommand(program);
|
|
1087
1295
|
program.exitOverride();
|
|
1088
1296
|
try {
|
|
1089
1297
|
await program.parseAsync(process.argv);
|
|
@@ -1091,7 +1299,7 @@ try {
|
|
|
1091
1299
|
const commanderError = error;
|
|
1092
1300
|
if (commanderError.code !== "commander.help" && commanderError.code !== "commander.version") {
|
|
1093
1301
|
logger.error("cli", "Command execution failed", error);
|
|
1094
|
-
console.error(
|
|
1302
|
+
console.error(chalk11.red(`
|
|
1095
1303
|
\u2716 Error: ${error.message}
|
|
1096
1304
|
`));
|
|
1097
1305
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gowelle/stint-agent",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Local agent for Stint - Project Assistant",
|
|
5
5
|
"author": "Gowelle John <gowelle.john@icloud.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"prepublishOnly": "npm run build"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@inquirer/prompts": "^
|
|
39
|
+
"@inquirer/prompts": "^8.1.0",
|
|
40
40
|
"chalk": "^5.3.0",
|
|
41
41
|
"commander": "^12.0.0",
|
|
42
42
|
"conf": "^12.0.0",
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
"eslint": "^8.56.0",
|
|
58
58
|
"tsup": "^8.0.1",
|
|
59
59
|
"typescript": "^5.3.3",
|
|
60
|
-
"vitest": "^
|
|
60
|
+
"vitest": "^4.0.16"
|
|
61
61
|
},
|
|
62
62
|
"engines": {
|
|
63
63
|
"node": ">=20.0.0"
|
|
64
64
|
}
|
|
65
|
-
}
|
|
65
|
+
}
|