@zhengjunyao/dsh-restart 0.1.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/CHANGELOG.md +27 -0
- package/LICENSE +21 -0
- package/README.md +116 -0
- package/README.zh.md +163 -0
- package/cordis.patch.yml +17 -0
- package/helper/restart-helper.mjs +828 -0
- package/lib/client.js +1706 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +1401 -0
- package/lib/types/client/RestartPanel.d.ts +5 -0
- package/lib/types/client/api.d.ts +230 -0
- package/lib/types/client/floating.d.ts +2 -0
- package/lib/types/client/index.d.ts +8 -0
- package/lib/types/client/overlay.d.ts +2 -0
- package/lib/types/client/state.d.ts +79 -0
- package/lib/types/config.d.ts +125 -0
- package/lib/types/index.d.ts +39 -0
- package/lib/types/launchd.d.ts +80 -0
- package/lib/types/restart.d.ts +236 -0
- package/lib/types/routes.d.ts +66 -0
- package/lib/types/tools.d.ts +25 -0
- package/package.json +96 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-restart — the restart engine (host half).
|
|
3
|
+
*
|
|
4
|
+
* A host cannot restart itself in place: the moment it exits, the browser has
|
|
5
|
+
* nothing to talk to, and any failure would be invisible. So the handoff goes
|
|
6
|
+
* through a detached helper process that survives the host:
|
|
7
|
+
*
|
|
8
|
+
* panel / tool ──POST /api/dsh-restart/restart──▶ host
|
|
9
|
+
* host ──writes pending-spec.json, spawns helper──▶ helper (detached)
|
|
10
|
+
* host ──SIGTERM after a short delay──▶ exit
|
|
11
|
+
* helper ──waits for the port to free, relaunches the same command──▶ new host
|
|
12
|
+
* helper ──status.json + fallback console──▶ the page shows progress / errors
|
|
13
|
+
*
|
|
14
|
+
* The relaunch reuses the exact invocation the running host was started with
|
|
15
|
+
* (`process.execArgv` + `argv[1:]`), so `dsh web --port 3080`, a `node` path
|
|
16
|
+
* override, a custom port and a custom cwd all survive a restart unchanged.
|
|
17
|
+
*/
|
|
18
|
+
import { type LaunchdInfo } from './launchd.ts';
|
|
19
|
+
import { type RestartConfig, type RestartRecord } from './config.ts';
|
|
20
|
+
/** Everything the panel needs to describe the running host. */
|
|
21
|
+
export interface HostInfo {
|
|
22
|
+
pid: number;
|
|
23
|
+
ppid: number;
|
|
24
|
+
startedAt: string;
|
|
25
|
+
uptimeMs: number;
|
|
26
|
+
/** Port the host is actually listening on. */
|
|
27
|
+
port: number;
|
|
28
|
+
host: string;
|
|
29
|
+
url: string;
|
|
30
|
+
cwd: string;
|
|
31
|
+
nodeVersion: string;
|
|
32
|
+
dshVersion: string;
|
|
33
|
+
profile: string;
|
|
34
|
+
/** Full relaunch command, for display. */
|
|
35
|
+
command: string;
|
|
36
|
+
/** True when this host was itself started by a restart helper. */
|
|
37
|
+
restarted: boolean;
|
|
38
|
+
platform: string;
|
|
39
|
+
logsDir: string;
|
|
40
|
+
statusFile: string;
|
|
41
|
+
helperFile: string;
|
|
42
|
+
helperExists: boolean;
|
|
43
|
+
/** macOS launchd job managing this host, when there is one. */
|
|
44
|
+
launchd: {
|
|
45
|
+
managed: boolean;
|
|
46
|
+
label: string;
|
|
47
|
+
state: string;
|
|
48
|
+
pid: number | null;
|
|
49
|
+
plistPath: string;
|
|
50
|
+
/** Log file the job's stdout/stderr land in ('' when the plist is silent). */
|
|
51
|
+
logFile: string;
|
|
52
|
+
/** Which strategy a restart will use right now. */
|
|
53
|
+
strategy: 'helper' | 'launchd';
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/** Live state written by the detached helper (all fields optional). */
|
|
57
|
+
export interface HelperStatus {
|
|
58
|
+
ok?: boolean;
|
|
59
|
+
/** Marker set by our own helper; absent on anything else bound to that port. */
|
|
60
|
+
helper?: string;
|
|
61
|
+
mode?: 'spawn' | 'observe';
|
|
62
|
+
phase?: string;
|
|
63
|
+
attempt?: number;
|
|
64
|
+
maxAttempts?: number;
|
|
65
|
+
port?: number;
|
|
66
|
+
url?: string;
|
|
67
|
+
fallbackPort?: number | null;
|
|
68
|
+
fallbackUrl?: string;
|
|
69
|
+
oldPid?: number | null;
|
|
70
|
+
childPid?: number | null;
|
|
71
|
+
childExit?: {
|
|
72
|
+
code: number | null;
|
|
73
|
+
signal: string | null;
|
|
74
|
+
at: string;
|
|
75
|
+
} | null;
|
|
76
|
+
startedAt?: string;
|
|
77
|
+
elapsedMs?: number;
|
|
78
|
+
readyAt?: string | null;
|
|
79
|
+
bootMs?: number | null;
|
|
80
|
+
failure?: {
|
|
81
|
+
kind: string;
|
|
82
|
+
message: string;
|
|
83
|
+
exitCode?: number | null;
|
|
84
|
+
} | null;
|
|
85
|
+
logFile?: string | null;
|
|
86
|
+
statusFile?: string | null;
|
|
87
|
+
errorLines?: {
|
|
88
|
+
t: number;
|
|
89
|
+
text: string;
|
|
90
|
+
}[];
|
|
91
|
+
tail?: string[];
|
|
92
|
+
dshVersion?: string | null;
|
|
93
|
+
profile?: string | null;
|
|
94
|
+
argv?: string[];
|
|
95
|
+
}
|
|
96
|
+
/** Launch specification handed to the helper. */
|
|
97
|
+
export interface RestartSpec {
|
|
98
|
+
port: number;
|
|
99
|
+
host: string;
|
|
100
|
+
url: string;
|
|
101
|
+
file: string;
|
|
102
|
+
args: string[];
|
|
103
|
+
cwd: string;
|
|
104
|
+
env: NodeJS.ProcessEnv;
|
|
105
|
+
oldPid: number;
|
|
106
|
+
logFile: string;
|
|
107
|
+
statusFile: string;
|
|
108
|
+
fallbackPort: number;
|
|
109
|
+
bootTimeoutMs: number;
|
|
110
|
+
maxAttempts: number;
|
|
111
|
+
killGraceMs: number;
|
|
112
|
+
portFreeTimeoutMs: number;
|
|
113
|
+
lingerMs: number;
|
|
114
|
+
ringLines: number;
|
|
115
|
+
dshVersion: string;
|
|
116
|
+
profile: string;
|
|
117
|
+
/**
|
|
118
|
+
* `spawn` — the helper relaunches the host itself.
|
|
119
|
+
* `observe` — something else owns the relaunch (launchd); the helper kicks it
|
|
120
|
+
* and then only watches, so two processes never race for the port.
|
|
121
|
+
*/
|
|
122
|
+
mode: 'spawn' | 'observe';
|
|
123
|
+
owner: string;
|
|
124
|
+
kickCommand: string[];
|
|
125
|
+
kickDelayMs: number;
|
|
126
|
+
observeLog: string;
|
|
127
|
+
/** Single self-contained report the helper writes when a boot fails. */
|
|
128
|
+
failureReport: string;
|
|
129
|
+
}
|
|
130
|
+
/** True when a pid is alive (signal 0 probe). */
|
|
131
|
+
export declare function isAlive(pid: number): boolean;
|
|
132
|
+
/** Detect (and cache) the launchd job managing this host. */
|
|
133
|
+
export declare function launchdInfo(force?: boolean): Promise<LaunchdInfo | null>;
|
|
134
|
+
/** The relaunch command, exactly as this host was started. */
|
|
135
|
+
export declare function launchSignature(): {
|
|
136
|
+
file: string;
|
|
137
|
+
args: string[];
|
|
138
|
+
cwd: string;
|
|
139
|
+
};
|
|
140
|
+
/** Describe the running host. */
|
|
141
|
+
export declare function hostInfo(options: {
|
|
142
|
+
port: number;
|
|
143
|
+
host: string;
|
|
144
|
+
url: string;
|
|
145
|
+
}): Promise<HostInfo>;
|
|
146
|
+
/** Build the helper spec for a restart of the current host. */
|
|
147
|
+
export declare function buildSpec(options: {
|
|
148
|
+
config: RestartConfig;
|
|
149
|
+
port: number;
|
|
150
|
+
host: string;
|
|
151
|
+
url: string;
|
|
152
|
+
/** Managing launchd job, when the restart will be delegated to it. */
|
|
153
|
+
launchd?: LaunchdInfo | null;
|
|
154
|
+
}): Promise<RestartSpec>;
|
|
155
|
+
/** Outcome of one restart request. */
|
|
156
|
+
export interface RestartOutcome {
|
|
157
|
+
ok: boolean;
|
|
158
|
+
error: string;
|
|
159
|
+
helperPid: number | null;
|
|
160
|
+
logFile: string;
|
|
161
|
+
statusFile: string;
|
|
162
|
+
specFile: string;
|
|
163
|
+
fallbackPort: number;
|
|
164
|
+
fallbackUrl: string;
|
|
165
|
+
/** Milliseconds after which this host stops serving (helper mode). */
|
|
166
|
+
exitInMs: number;
|
|
167
|
+
/** Which strategy actually ran. */
|
|
168
|
+
mode: 'helper' | 'launchd';
|
|
169
|
+
record: RestartRecord;
|
|
170
|
+
/**
|
|
171
|
+
* Perform the handover. MUST be called after the HTTP reply is on the wire:
|
|
172
|
+
* in launchd mode the helper kickstart terminates this process.
|
|
173
|
+
*/
|
|
174
|
+
commit: () => Promise<void>;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Hand the restart over to a detached helper.
|
|
178
|
+
*
|
|
179
|
+
* Returns as soon as the helper is running; the caller is responsible for
|
|
180
|
+
* answering the HTTP request first and only then ending this process (see
|
|
181
|
+
* {@link scheduleSelfExit}), so the browser always gets a definite reply.
|
|
182
|
+
*
|
|
183
|
+
* @param options - config, listen address, and who asked.
|
|
184
|
+
*/
|
|
185
|
+
export declare function requestRestart(options: {
|
|
186
|
+
config: RestartConfig;
|
|
187
|
+
port: number;
|
|
188
|
+
host: string;
|
|
189
|
+
url: string;
|
|
190
|
+
source: string;
|
|
191
|
+
reason: string;
|
|
192
|
+
exitDelayMs?: number;
|
|
193
|
+
}): Promise<RestartOutcome>;
|
|
194
|
+
/**
|
|
195
|
+
* End this host so the helper can take over.
|
|
196
|
+
*
|
|
197
|
+
* SIGTERM first (lets DSH close sessions and release the port), then a hard
|
|
198
|
+
* exit as a backstop — the helper SIGKILLs anything still holding the port
|
|
199
|
+
* after its own grace period.
|
|
200
|
+
* @param delayMs - how long to wait before signalling (the HTTP reply needs to flush).
|
|
201
|
+
*/
|
|
202
|
+
export declare function scheduleSelfExit(delayMs: number): void;
|
|
203
|
+
/** Read the live helper status, if any. */
|
|
204
|
+
export declare function readHelperStatus(): Promise<{
|
|
205
|
+
status: HelperStatus | null;
|
|
206
|
+
alive: boolean;
|
|
207
|
+
ageMs: number | null;
|
|
208
|
+
}>;
|
|
209
|
+
/** A log tail plus the lines that look like errors. */
|
|
210
|
+
export interface LogTail {
|
|
211
|
+
file: string;
|
|
212
|
+
exists: boolean;
|
|
213
|
+
mtime: string;
|
|
214
|
+
text: string;
|
|
215
|
+
lines: string[];
|
|
216
|
+
errorLines: string[];
|
|
217
|
+
}
|
|
218
|
+
/** Tail a log file (missing files come back as an empty tail, not an error). */
|
|
219
|
+
export declare function tailFile(file: string, limit: number): Promise<LogTail>;
|
|
220
|
+
/** Where the helper drops the copy-ready failure report. */
|
|
221
|
+
export declare function failureReportPath(): string;
|
|
222
|
+
/** Read the last failure report ('' when the last restart did not fail). */
|
|
223
|
+
export declare function readFailureReport(): Promise<{
|
|
224
|
+
text: string;
|
|
225
|
+
file: string;
|
|
226
|
+
exists: boolean;
|
|
227
|
+
}>;
|
|
228
|
+
/** The newest log file in the logs directory (null when none exist). */
|
|
229
|
+
export declare function newestLogFile(): Promise<string | null>;
|
|
230
|
+
/** List recent log files (newest first). */
|
|
231
|
+
export declare function listLogs(limit?: number): Promise<{
|
|
232
|
+
name: string;
|
|
233
|
+
file: string;
|
|
234
|
+
size: number;
|
|
235
|
+
mtime: string;
|
|
236
|
+
}[]>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-restart — loopback HTTP routes for the web panel.
|
|
3
|
+
*
|
|
4
|
+
* Route family: /api/dsh-restart/*. Every route is loopback-only (127.0.0.1 /
|
|
5
|
+
* ::1, same-origin), matching the other dsh-* panels.
|
|
6
|
+
*
|
|
7
|
+
* GET /status host + live helper + config, plus the last restarts
|
|
8
|
+
* GET /probe tiny liveness probe the page polls while reconnecting
|
|
9
|
+
* POST /restart hand the restart to the detached helper, then exit
|
|
10
|
+
* GET /logs boot-log tail (and the lines that look like errors)
|
|
11
|
+
* GET /history one record per requested restart
|
|
12
|
+
* POST /config patch / reset the plugin config
|
|
13
|
+
* GET /helper the helper's live status through the host (proxy)
|
|
14
|
+
* POST /helper/retry ask a failed helper to try again
|
|
15
|
+
*/
|
|
16
|
+
import type { WebRoute } from '@deepseek-ai/dsh-host-webserver';
|
|
17
|
+
import { type RestartConfig } from './config.ts';
|
|
18
|
+
import { type HelperStatus, type HostInfo } from './restart.ts';
|
|
19
|
+
/** Route paths. */
|
|
20
|
+
export declare const RESTART_API: {
|
|
21
|
+
readonly status: "/api/dsh-restart/status";
|
|
22
|
+
readonly probe: "/api/dsh-restart/probe";
|
|
23
|
+
readonly restart: "/api/dsh-restart/restart";
|
|
24
|
+
readonly logs: "/api/dsh-restart/logs";
|
|
25
|
+
readonly history: "/api/dsh-restart/history";
|
|
26
|
+
readonly config: "/api/dsh-restart/config";
|
|
27
|
+
readonly helper: "/api/dsh-restart/helper";
|
|
28
|
+
readonly helperRetry: "/api/dsh-restart/helper/retry";
|
|
29
|
+
};
|
|
30
|
+
/** Where this host is reachable (filled in by the plugin at mount time). */
|
|
31
|
+
export interface RouteContext {
|
|
32
|
+
/** Listening port of the host's web server. */
|
|
33
|
+
port: number;
|
|
34
|
+
/** Bind host. */
|
|
35
|
+
host: string;
|
|
36
|
+
/** Base URL used in links and the helper spec. */
|
|
37
|
+
url: string;
|
|
38
|
+
}
|
|
39
|
+
/** Status payload returned to the panel. */
|
|
40
|
+
export interface RestartStatusPayload {
|
|
41
|
+
ok: true;
|
|
42
|
+
host: HostInfo;
|
|
43
|
+
helper: HelperStatus | null;
|
|
44
|
+
helperAlive: boolean;
|
|
45
|
+
helperAgeMs: number | null;
|
|
46
|
+
config: RestartConfig;
|
|
47
|
+
configFile: string;
|
|
48
|
+
configExists: boolean;
|
|
49
|
+
statusFile: string;
|
|
50
|
+
/** Where the detached recovery console is reachable (after a restart). */
|
|
51
|
+
consoleUrl: string;
|
|
52
|
+
/** launchd job managing this host, when there is one. */
|
|
53
|
+
launchd: {
|
|
54
|
+
managed: boolean;
|
|
55
|
+
label: string;
|
|
56
|
+
state: string;
|
|
57
|
+
logFile: string;
|
|
58
|
+
strategy: string;
|
|
59
|
+
} | null;
|
|
60
|
+
/** Restarts requested through this plugin, newest first. */
|
|
61
|
+
history: unknown[];
|
|
62
|
+
logFiles: unknown[];
|
|
63
|
+
endpoints: typeof RESTART_API;
|
|
64
|
+
}
|
|
65
|
+
/** Build the route list for ctx.webServer.register. */
|
|
66
|
+
export declare function makeRoutes(deps: RouteContext): WebRoute[];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-restart — model-facing tools.
|
|
3
|
+
*
|
|
4
|
+
* dsh_restart_status read-only: host identity, live helper state, and the
|
|
5
|
+
* lines of the last boot log that look like errors.
|
|
6
|
+
* dsh_restart restart the host through the detached helper.
|
|
7
|
+
*
|
|
8
|
+
* The write tool demands `confirm: true`, because restarting DSH ends the
|
|
9
|
+
* current turn and the current session's connection: an agent must have asked
|
|
10
|
+
* the user first (the local standing rule is that DSH is never restarted
|
|
11
|
+
* without explicit consent).
|
|
12
|
+
*/
|
|
13
|
+
import { type ToolDefinition } from '@deepseek-ai/dsh-tools';
|
|
14
|
+
import type { RouteContext } from './routes.ts';
|
|
15
|
+
/** Shared tool dependencies. */
|
|
16
|
+
export interface ToolContext {
|
|
17
|
+
/** Where this host listens. */
|
|
18
|
+
endpoint: RouteContext;
|
|
19
|
+
}
|
|
20
|
+
/** Tool: restart status, live helper state, last boot errors. */
|
|
21
|
+
export declare function restartStatusTool(ctx: ToolContext): ToolDefinition;
|
|
22
|
+
/** Tool: restart the host. */
|
|
23
|
+
export declare function restartTool(ctx: ToolContext): ToolDefinition;
|
|
24
|
+
/** Build the tool roster. */
|
|
25
|
+
export declare function buildTools(ctx: ToolContext): ToolDefinition[];
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zhengjunyao/dsh-restart",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "One-click restart for DeepSeek Harness: a web button (plus a dsh_restart agent tool) hands the relaunch to a detached helper that waits for the port to free, relaunches the exact same command, streams the new host's output, auto-reconnects the page — and shows the boot errors in a recovery console when the new host dies",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./lib/index.js",
|
|
9
|
+
"./client": "./lib/client.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"dsh": {
|
|
13
|
+
"bundle": {
|
|
14
|
+
"patch": "./cordis.patch.yml"
|
|
15
|
+
},
|
|
16
|
+
"client": {
|
|
17
|
+
"inject": [
|
|
18
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
19
|
+
"@deepseek-ai/dsh-client-connection",
|
|
20
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
21
|
+
],
|
|
22
|
+
"platform": "web"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"dsh": ">=0.1.5-rc.1"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"lib",
|
|
30
|
+
"helper",
|
|
31
|
+
"cordis.patch.yml",
|
|
32
|
+
"README.md",
|
|
33
|
+
"README.zh.md",
|
|
34
|
+
"LICENSE",
|
|
35
|
+
"CHANGELOG.md"
|
|
36
|
+
],
|
|
37
|
+
"keywords": [
|
|
38
|
+
"dsh",
|
|
39
|
+
"dsh-plugin",
|
|
40
|
+
"deepseek-harness",
|
|
41
|
+
"restart",
|
|
42
|
+
"reload",
|
|
43
|
+
"supervisor",
|
|
44
|
+
"重启",
|
|
45
|
+
"panel"
|
|
46
|
+
],
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsc -p tsconfig.build.json && tsdown",
|
|
53
|
+
"bundle": "tsdown",
|
|
54
|
+
"typecheck": "tsc --noEmit",
|
|
55
|
+
"test": "node tests/smoke.mjs && node tests/helper.mjs && node tests/routes.mjs && node tests/handoff.mjs && node tests/launchd.mjs",
|
|
56
|
+
"verify": "node scripts/portability.mjs --health /api/dsh-restart/probe --restart-route /api/dsh-restart/restart",
|
|
57
|
+
"verify:quick": "node scripts/portability.mjs --skip-audit --health /api/dsh-restart/probe",
|
|
58
|
+
"prepare": "npm run build"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
62
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-alpha.1 || ^0.1.5-rc.1",
|
|
63
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-alpha.1 || ^0.1.5-rc.1",
|
|
64
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-alpha.1 || ^0.1.5-rc.1",
|
|
65
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-alpha.1 || ^0.1.5-rc.1",
|
|
66
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || ^0.1.1-rc.1 || ^0.1.2-alpha.1 || ^0.1.5-rc.1",
|
|
67
|
+
"react": "^18.2.0",
|
|
68
|
+
"react-dom": "^18.2.0"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
72
|
+
"@deepseek-ai/dsh-client-connection": "0.1.5-rc.1",
|
|
73
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.1",
|
|
74
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.1",
|
|
75
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.1",
|
|
76
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.5-rc.1",
|
|
77
|
+
"@deepseek-ai/dsh-llm": "0.1.5-rc.1",
|
|
78
|
+
"@deepseek-ai/dsh-system-prompt": "0.1.5-rc.1",
|
|
79
|
+
"@deepseek-ai/dsh-tools": "0.1.5-rc.1",
|
|
80
|
+
"@types/node": "^22.20.0",
|
|
81
|
+
"@types/react": "~18.3.1",
|
|
82
|
+
"@types/react-dom": "~18.3.5",
|
|
83
|
+
"lightningcss": "1.32.0",
|
|
84
|
+
"react": "^18.3.1",
|
|
85
|
+
"react-dom": "^18.3.1",
|
|
86
|
+
"tsdown": "0.22.2",
|
|
87
|
+
"typescript": "~5.7.2"
|
|
88
|
+
},
|
|
89
|
+
"repository": {
|
|
90
|
+
"type": "git",
|
|
91
|
+
"url": "https://github.com/zhengjy01/dsh-restart"
|
|
92
|
+
},
|
|
93
|
+
"publishConfig": {
|
|
94
|
+
"access": "public"
|
|
95
|
+
}
|
|
96
|
+
}
|