@exaudeus/workrail 3.19.1 → 3.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/console/assets/index-B8NW82uK.css +1 -0
- package/dist/console/assets/index-De5T1Dpm.js +28 -0
- package/dist/console/index.html +2 -2
- package/dist/di/container.js +8 -2
- package/dist/infrastructure/session/HttpServer.d.ts +2 -0
- package/dist/infrastructure/session/HttpServer.js +15 -0
- package/dist/manifest.json +23 -23
- package/dist/mcp/transports/shutdown-hooks.d.ts +5 -0
- package/dist/mcp/transports/shutdown-hooks.js +19 -0
- package/dist/mcp/transports/stdio-entry.js +8 -0
- package/dist/v2/infra/local/session-lock/index.d.ts +1 -0
- package/dist/v2/infra/local/session-lock/index.js +31 -0
- package/package.json +8 -3
- package/dist/console/assets/index-QhCFuxQV.js +0 -28
- package/dist/console/assets/index-ibLhWBmX.css +0 -1
package/dist/console/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>WorkRail Console</title>
|
|
7
|
-
<script type="module" crossorigin src="/console/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/console/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/console/assets/index-De5T1Dpm.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/console/assets/index-B8NW82uK.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
package/dist/di/container.js
CHANGED
|
@@ -362,8 +362,14 @@ async function startAsyncServices() {
|
|
|
362
362
|
const flags = tsyringe_1.container.resolve(tokens_js_1.DI.Infra.FeatureFlags);
|
|
363
363
|
if (flags.isEnabled('sessionTools')) {
|
|
364
364
|
const server = tsyringe_1.container.resolve(tokens_js_1.DI.Infra.HttpServer);
|
|
365
|
-
|
|
366
|
-
|
|
365
|
+
try {
|
|
366
|
+
await server.start();
|
|
367
|
+
console.error('[DI] HTTP server started');
|
|
368
|
+
}
|
|
369
|
+
catch (httpError) {
|
|
370
|
+
const message = httpError instanceof Error ? httpError.message : String(httpError);
|
|
371
|
+
console.error(`[DI] Dashboard HTTP server unavailable: ${message}. MCP tools will still work.`);
|
|
372
|
+
}
|
|
367
373
|
}
|
|
368
374
|
asyncInitialized = true;
|
|
369
375
|
}
|
|
@@ -33,6 +33,7 @@ export declare class HttpServer {
|
|
|
33
33
|
private isPrimary;
|
|
34
34
|
private lockFile;
|
|
35
35
|
private heartbeat;
|
|
36
|
+
private _stopPromise;
|
|
36
37
|
constructor(sessionManager: SessionManager, processLifecyclePolicy: ProcessLifecyclePolicy, processSignals: ProcessSignals, shutdownEvents: ShutdownEvents, dashboardMode: DashboardMode, browserBehavior: BrowserBehavior);
|
|
37
38
|
private config;
|
|
38
39
|
setConfig(config: ServerConfig): this;
|
|
@@ -48,6 +49,7 @@ export declare class HttpServer {
|
|
|
48
49
|
private printBanner;
|
|
49
50
|
openDashboard(sessionId?: string): Promise<string>;
|
|
50
51
|
stop(): Promise<void>;
|
|
52
|
+
private _runStop;
|
|
51
53
|
mountRoutes(installer: (app: Application) => (() => void) | void): void;
|
|
52
54
|
private readonly _routeDisposers;
|
|
53
55
|
finalize(): void;
|
|
@@ -42,6 +42,7 @@ let HttpServer = class HttpServer {
|
|
|
42
42
|
this.server = null;
|
|
43
43
|
this.baseUrl = '';
|
|
44
44
|
this.isPrimary = false;
|
|
45
|
+
this._stopPromise = null;
|
|
45
46
|
this.config = {};
|
|
46
47
|
this._routeDisposers = [];
|
|
47
48
|
this.port = 3456;
|
|
@@ -331,6 +332,7 @@ let HttpServer = class HttpServer {
|
|
|
331
332
|
});
|
|
332
333
|
}
|
|
333
334
|
async start() {
|
|
335
|
+
this._stopPromise = null;
|
|
334
336
|
const mode = this.config.dashboardMode ?? this.dashboardMode;
|
|
335
337
|
if (mode.kind === 'legacy') {
|
|
336
338
|
console.error('[Dashboard] Unified dashboard disabled, using legacy mode');
|
|
@@ -556,6 +558,7 @@ let HttpServer = class HttpServer {
|
|
|
556
558
|
throw error;
|
|
557
559
|
}
|
|
558
560
|
}
|
|
561
|
+
this.server = null;
|
|
559
562
|
throw new Error('No available ports in range 3457-3499');
|
|
560
563
|
}
|
|
561
564
|
printBanner() {
|
|
@@ -570,6 +573,10 @@ let HttpServer = class HttpServer {
|
|
|
570
573
|
console.error();
|
|
571
574
|
}
|
|
572
575
|
async openDashboard(sessionId) {
|
|
576
|
+
if (!this.baseUrl) {
|
|
577
|
+
throw new Error('Dashboard is unavailable -- the HTTP server did not start successfully ' +
|
|
578
|
+
'(likely due to port exhaustion). MCP tools still work normally.');
|
|
579
|
+
}
|
|
573
580
|
let url = this.baseUrl;
|
|
574
581
|
if (sessionId) {
|
|
575
582
|
url += `?session=${sessionId}`;
|
|
@@ -587,6 +594,14 @@ let HttpServer = class HttpServer {
|
|
|
587
594
|
return url;
|
|
588
595
|
}
|
|
589
596
|
async stop() {
|
|
597
|
+
if (this._stopPromise !== null)
|
|
598
|
+
return this._stopPromise;
|
|
599
|
+
if (this.server === null)
|
|
600
|
+
return Promise.resolve();
|
|
601
|
+
this._stopPromise = this._runStop();
|
|
602
|
+
return this._stopPromise;
|
|
603
|
+
}
|
|
604
|
+
async _runStop() {
|
|
590
605
|
this.heartbeat.stop();
|
|
591
606
|
this.sessionManager.unwatchAll();
|
|
592
607
|
for (const dispose of this._routeDisposers) {
|
package/dist/manifest.json
CHANGED
|
@@ -369,16 +369,16 @@
|
|
|
369
369
|
"sha256": "5fe866e54f796975dec5d8ba9983aefd86074db212d3fccd64eed04bc9f0b3da",
|
|
370
370
|
"bytes": 8011
|
|
371
371
|
},
|
|
372
|
-
"console/assets/index-
|
|
373
|
-
"sha256": "
|
|
374
|
-
"bytes":
|
|
372
|
+
"console/assets/index-B8NW82uK.css": {
|
|
373
|
+
"sha256": "8588d6702df899c724f5abce3e45dd4a6f7ee06bf2b280cb3909f9cabcc0a32c",
|
|
374
|
+
"bytes": 58801
|
|
375
375
|
},
|
|
376
|
-
"console/assets/index-
|
|
377
|
-
"sha256": "
|
|
378
|
-
"bytes":
|
|
376
|
+
"console/assets/index-De5T1Dpm.js": {
|
|
377
|
+
"sha256": "bad5fc857501a1253c800b6863e95cc854f3c8a52fea80959306ba32e15fd907",
|
|
378
|
+
"bytes": 721395
|
|
379
379
|
},
|
|
380
380
|
"console/index.html": {
|
|
381
|
-
"sha256": "
|
|
381
|
+
"sha256": "3165437d9c2abc907ab1333dde87b0064e7c8fba62c3ffd2567e8bc02e75329b",
|
|
382
382
|
"bytes": 417
|
|
383
383
|
},
|
|
384
384
|
"core/error-handler.d.ts": {
|
|
@@ -394,8 +394,8 @@
|
|
|
394
394
|
"bytes": 620
|
|
395
395
|
},
|
|
396
396
|
"di/container.js": {
|
|
397
|
-
"sha256": "
|
|
398
|
-
"bytes":
|
|
397
|
+
"sha256": "7956cb925d40f61746ccdcec245c5ee40d7d317893eff240a10cff595304d467",
|
|
398
|
+
"bytes": 22026
|
|
399
399
|
},
|
|
400
400
|
"di/tokens.d.ts": {
|
|
401
401
|
"sha256": "04db6db34348aa36d897c85ab07eb1a386cb04e3595dbcb33525bd33974111ef",
|
|
@@ -542,12 +542,12 @@
|
|
|
542
542
|
"bytes": 818
|
|
543
543
|
},
|
|
544
544
|
"infrastructure/session/HttpServer.d.ts": {
|
|
545
|
-
"sha256": "
|
|
546
|
-
"bytes":
|
|
545
|
+
"sha256": "79c0d8855d9437084756186f5e115aab82c829f48bafc1a5742903a1e7d808b6",
|
|
546
|
+
"bytes": 2025
|
|
547
547
|
},
|
|
548
548
|
"infrastructure/session/HttpServer.js": {
|
|
549
|
-
"sha256": "
|
|
550
|
-
"bytes":
|
|
549
|
+
"sha256": "3f2bc1fb56b8191da261567eb7fb8e78f4c3e33b54c71da361aeea51d047ccd8",
|
|
550
|
+
"bytes": 30743
|
|
551
551
|
},
|
|
552
552
|
"infrastructure/session/SessionDataNormalizer.d.ts": {
|
|
553
553
|
"sha256": "c89bb5e00d7d01fb4aa6d0095602541de53c425c6b99b67fa8367eb29cb63e9e",
|
|
@@ -1102,20 +1102,20 @@
|
|
|
1102
1102
|
"bytes": 3534
|
|
1103
1103
|
},
|
|
1104
1104
|
"mcp/transports/shutdown-hooks.d.ts": {
|
|
1105
|
-
"sha256": "
|
|
1106
|
-
"bytes":
|
|
1105
|
+
"sha256": "abf3799e44183c8a7e3614e2f14c1d7c8c4bb4ce0b720d3005ee165e4dd6f211",
|
|
1106
|
+
"bytes": 547
|
|
1107
1107
|
},
|
|
1108
1108
|
"mcp/transports/shutdown-hooks.js": {
|
|
1109
|
-
"sha256": "
|
|
1110
|
-
"bytes":
|
|
1109
|
+
"sha256": "b44d0daaabfc4a896a910691637473d238127157f762743fec35625b6d12d4eb",
|
|
1110
|
+
"bytes": 2701
|
|
1111
1111
|
},
|
|
1112
1112
|
"mcp/transports/stdio-entry.d.ts": {
|
|
1113
1113
|
"sha256": "4ced3c9e00ef67555781dea74315290eea8a9dbffd38155bc00c3fb07b0c1794",
|
|
1114
1114
|
"bytes": 59
|
|
1115
1115
|
},
|
|
1116
1116
|
"mcp/transports/stdio-entry.js": {
|
|
1117
|
-
"sha256": "
|
|
1118
|
-
"bytes":
|
|
1117
|
+
"sha256": "d934d0a7bb5a5d4331ce424aa754c063dac0a2f914d6b9d5f75489740d325b0a",
|
|
1118
|
+
"bytes": 4039
|
|
1119
1119
|
},
|
|
1120
1120
|
"mcp/transports/transport-mode.d.ts": {
|
|
1121
1121
|
"sha256": "1c59128ab0174bd2a113fff17521e6339ca367f2b8980c2f2c164ec393c10518",
|
|
@@ -2278,12 +2278,12 @@
|
|
|
2278
2278
|
"bytes": 7393
|
|
2279
2279
|
},
|
|
2280
2280
|
"v2/infra/local/session-lock/index.d.ts": {
|
|
2281
|
-
"sha256": "
|
|
2282
|
-
"bytes":
|
|
2281
|
+
"sha256": "e180a4202587af03e09dc82e2d8557ee2d3139ac6c5f1edee9a277a7032b9986",
|
|
2282
|
+
"bytes": 883
|
|
2283
2283
|
},
|
|
2284
2284
|
"v2/infra/local/session-lock/index.js": {
|
|
2285
|
-
"sha256": "
|
|
2286
|
-
"bytes":
|
|
2285
|
+
"sha256": "a1cd3eaea35faa014922fe1502a9e029a58528421586c67ab44dc7df0183a0fe",
|
|
2286
|
+
"bytes": 2793
|
|
2287
2287
|
},
|
|
2288
2288
|
"v2/infra/local/session-store/index.d.ts": {
|
|
2289
2289
|
"sha256": "33b18ccce92374f8e444a61c63238634087d222f09e834b49dd2ea38d2be3796",
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
export interface ShutdownHookOptions {
|
|
2
2
|
readonly onBeforeTerminate: () => Promise<void>;
|
|
3
|
+
readonly stdout?: NodeJS.WritableStream;
|
|
3
4
|
}
|
|
4
5
|
export declare function wireShutdownHooks(opts: ShutdownHookOptions): void;
|
|
6
|
+
export interface StdoutShutdownOptions {
|
|
7
|
+
readonly stdout?: NodeJS.WritableStream;
|
|
8
|
+
}
|
|
9
|
+
export declare function wireStdoutShutdown(opts?: StdoutShutdownOptions): void;
|
|
5
10
|
export interface StdinShutdownOptions {
|
|
6
11
|
readonly stdin?: NodeJS.ReadableStream;
|
|
7
12
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.wireShutdownHooks = wireShutdownHooks;
|
|
4
|
+
exports.wireStdoutShutdown = wireStdoutShutdown;
|
|
4
5
|
exports.wireStdinShutdown = wireStdinShutdown;
|
|
5
6
|
const container_js_1 = require("../../di/container.js");
|
|
6
7
|
const tokens_js_1 = require("../../di/tokens.js");
|
|
@@ -8,6 +9,10 @@ function wireShutdownHooks(opts) {
|
|
|
8
9
|
const shutdownEvents = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ShutdownEvents);
|
|
9
10
|
const processSignals = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ProcessSignals);
|
|
10
11
|
const terminator = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ProcessTerminator);
|
|
12
|
+
const stdout = opts.stdout ?? process.stdout;
|
|
13
|
+
stdout.on('error', () => {
|
|
14
|
+
stdout.emit('drain');
|
|
15
|
+
});
|
|
11
16
|
processSignals.on('SIGINT', () => shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGINT' }));
|
|
12
17
|
processSignals.on('SIGTERM', () => shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGTERM' }));
|
|
13
18
|
processSignals.on('SIGHUP', () => shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGHUP' }));
|
|
@@ -29,6 +34,20 @@ function wireShutdownHooks(opts) {
|
|
|
29
34
|
})();
|
|
30
35
|
});
|
|
31
36
|
}
|
|
37
|
+
function wireStdoutShutdown(opts) {
|
|
38
|
+
const shutdownEvents = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ShutdownEvents);
|
|
39
|
+
const stdout = opts?.stdout ?? process.stdout;
|
|
40
|
+
stdout.on('error', (err) => {
|
|
41
|
+
const code = err.code;
|
|
42
|
+
if (code === 'EPIPE' || code === 'ERR_STREAM_DESTROYED') {
|
|
43
|
+
console.error('[MCP] stdout pipe broken (client disconnected), initiating shutdown');
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
console.error('[MCP] stdout error:', err);
|
|
47
|
+
}
|
|
48
|
+
shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGHUP' });
|
|
49
|
+
});
|
|
50
|
+
}
|
|
32
51
|
function wireStdinShutdown(opts) {
|
|
33
52
|
const shutdownEvents = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ShutdownEvents);
|
|
34
53
|
const stdin = opts?.stdin ?? process.stdin;
|
|
@@ -46,6 +46,13 @@ async function fetchInitialRootsWithTimeout(server) {
|
|
|
46
46
|
]);
|
|
47
47
|
}
|
|
48
48
|
async function startStdioServer() {
|
|
49
|
+
process.on('uncaughtException', (err) => {
|
|
50
|
+
console.error('[MCP] Uncaught exception -- process will exit:', err);
|
|
51
|
+
});
|
|
52
|
+
process.on('unhandledRejection', (reason) => {
|
|
53
|
+
console.error('[MCP] Unhandled promise rejection:', reason);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
});
|
|
49
56
|
const { server, ctx, rootsManager } = await (0, server_js_1.composeServer)();
|
|
50
57
|
const { StdioServerTransport } = await Promise.resolve().then(() => __importStar(require('@modelcontextprotocol/sdk/server/stdio.js')));
|
|
51
58
|
const { RootsListChangedNotificationSchema, } = await Promise.resolve().then(() => __importStar(require('@modelcontextprotocol/sdk/types.js')));
|
|
@@ -59,6 +66,7 @@ async function startStdioServer() {
|
|
|
59
66
|
console.error('[Roots] Failed to fetch updated roots after change notification');
|
|
60
67
|
}
|
|
61
68
|
});
|
|
69
|
+
(0, shutdown_hooks_js_1.wireStdoutShutdown)();
|
|
62
70
|
const transport = new StdioServerTransport();
|
|
63
71
|
await server.connect(transport);
|
|
64
72
|
console.error('[Transport] WorkRail MCP Server running on stdio');
|
|
@@ -9,6 +9,7 @@ export declare class LocalSessionLockV2 implements SessionLockPortV2 {
|
|
|
9
9
|
private readonly fs;
|
|
10
10
|
private readonly clock;
|
|
11
11
|
constructor(dataDir: DataDirPortV2, fs: FileSystemPortV2, clock: TimeClockPortV2);
|
|
12
|
+
private clearIfStaleLock;
|
|
12
13
|
acquire(sessionId: SessionId): ResultAsync<SessionLockHandleV2, SessionLockError>;
|
|
13
14
|
release(handle: SessionLockHandleV2): ResultAsync<void, SessionLockError>;
|
|
14
15
|
}
|
|
@@ -1,12 +1,42 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LocalSessionLockV2 = void 0;
|
|
4
|
+
const neverthrow_1 = require("neverthrow");
|
|
4
5
|
class LocalSessionLockV2 {
|
|
5
6
|
constructor(dataDir, fs, clock) {
|
|
6
7
|
this.dataDir = dataDir;
|
|
7
8
|
this.fs = fs;
|
|
8
9
|
this.clock = clock;
|
|
9
10
|
}
|
|
11
|
+
clearIfStaleLock(lockPath) {
|
|
12
|
+
return this.fs
|
|
13
|
+
.readFileUtf8(lockPath)
|
|
14
|
+
.map((content) => {
|
|
15
|
+
try {
|
|
16
|
+
const data = JSON.parse(content);
|
|
17
|
+
const pid = typeof data.pid === 'number' ? data.pid : null;
|
|
18
|
+
if (pid === null)
|
|
19
|
+
return false;
|
|
20
|
+
try {
|
|
21
|
+
process.kill(pid, 0);
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
return e.code === 'ESRCH';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
.andThen((isStale) => {
|
|
33
|
+
if (!isStale)
|
|
34
|
+
return (0, neverthrow_1.okAsync)(undefined);
|
|
35
|
+
console.error(`[SessionLock] Removing stale lock at ${lockPath} (process no longer alive)`);
|
|
36
|
+
return this.fs.unlink(lockPath);
|
|
37
|
+
})
|
|
38
|
+
.orElse(() => (0, neverthrow_1.okAsync)(undefined));
|
|
39
|
+
}
|
|
10
40
|
acquire(sessionId) {
|
|
11
41
|
const sessionDir = this.dataDir.sessionDir(sessionId);
|
|
12
42
|
const lockPath = this.dataDir.sessionLockPath(sessionId);
|
|
@@ -23,6 +53,7 @@ class LocalSessionLockV2 {
|
|
|
23
53
|
};
|
|
24
54
|
return this.fs
|
|
25
55
|
.mkdirp(sessionDir)
|
|
56
|
+
.andThen(() => this.clearIfStaleLock(lockPath))
|
|
26
57
|
.andThen(() => this.fs.openExclusive(lockPath, new TextEncoder().encode(JSON.stringify({
|
|
27
58
|
v: 1,
|
|
28
59
|
sessionId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exaudeus/workrail",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.20.1",
|
|
4
4
|
"description": "Step-by-step workflow enforcement for AI agents via MCP",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -47,6 +47,8 @@
|
|
|
47
47
|
"validate:workflow-discovery": "node scripts/validate-workflow-discovery.js",
|
|
48
48
|
"precommit": "npm run validate:registry",
|
|
49
49
|
"preinstall": "node -e \"const v=parseInt(process.versions.node.split('.')[0],10); if(v<20){console.error('WorkRail requires Node.js >=20. Current: '+process.versions.node+'\\nPlease upgrade: https://nodejs.org/'); process.exit(1);}\"",
|
|
50
|
+
"dev:mcp": "pkill -f 'dist/mcp-server.js' 2>/dev/null; sleep 0.5; WORKRAIL_TRANSPORT=http WORKRAIL_ENABLE_SESSION_TOOLS=true node dist/mcp-server.js",
|
|
51
|
+
"dev:mcp:watch": "WORKRAIL_TRANSPORT=http WORKRAIL_ENABLE_SESSION_TOOLS=true nodemon --watch dist --ext js --delay 2 --exec 'node dist/mcp-server.js'",
|
|
50
52
|
"web:dev": "npm run build && WORKRAIL_ENABLE_SESSION_TOOLS=true node dist/mcp-server.js",
|
|
51
53
|
"web:ci": "WORKRAIL_ENABLE_SESSION_TOOLS=true node dist/mcp-server.js",
|
|
52
54
|
"web:typecheck": "tsc -p tsconfig.web.json",
|
|
@@ -113,17 +115,20 @@
|
|
|
113
115
|
"@semantic-release/exec": "^7.1.0",
|
|
114
116
|
"@semantic-release/git": "^10.0.1",
|
|
115
117
|
"@semantic-release/github": "^12.0.2",
|
|
118
|
+
"@testing-library/react": "^16.3.2",
|
|
119
|
+
"@testing-library/user-event": "^14.6.1",
|
|
116
120
|
"@types/cors": "^2.8.19",
|
|
117
121
|
"@types/express": "^5.0.3",
|
|
118
122
|
"@types/node": "^20.19.9",
|
|
119
123
|
"@types/semver": "^7.7.0",
|
|
120
124
|
"@vitest/ui": "^3.2.4",
|
|
121
125
|
"conventional-changelog-conventionalcommits": "^9.1.0",
|
|
122
|
-
"fast-check": "^
|
|
126
|
+
"fast-check": "^4.6.0",
|
|
123
127
|
"happy-dom": "^20.0.11",
|
|
124
|
-
"jsdom": "^
|
|
128
|
+
"jsdom": "^29.0.2",
|
|
125
129
|
"lit": "^3.3.1",
|
|
126
130
|
"node-fetch": "^3.3.2",
|
|
131
|
+
"nodemon": "^3.0.0",
|
|
127
132
|
"semantic-release": "^25.0.3",
|
|
128
133
|
"ts-morph": "^27.0.2",
|
|
129
134
|
"typescript": "^5.9.3",
|