@norman-else/dsh-claude 0.1.7 → 0.1.8

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/lib/bin.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.mjs","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { access } from 'node:fs/promises'\r\nimport { constants } from 'node:fs'\r\nimport { homedir } from 'node:os'\r\nimport { delimiter, isAbsolute, join } from 'node:path'\r\nimport { spawnSync } from 'node:child_process'\r\nimport { scrubbedParentEnv } from '@deepseek-ai/dsh-subprocess'\r\nimport { parseClaudeVersion } from './executable.ts'\r\nimport { ensureManagedPreset, removeManagedPreset } from './preset-installer.ts'\r\n\r\nfunction option(name: string): string | undefined {\r\n const index = process.argv.indexOf(name)\r\n return index < 0 ? undefined : process.argv[index + 1]\r\n}\r\n\r\nasync function executable(configured?: string): Promise<string | undefined> {\r\n const candidates: string[] = []\r\n if (configured !== undefined) candidates.push(configured)\r\n else {\r\n for (const directory of (process.env.PATH ?? '').split(delimiter)) {\r\n if (directory.length > 0) candidates.push(join(directory, 'claude'))\r\n }\r\n candidates.push(join(homedir(), '.local', 'bin', 'claude'), '/opt/homebrew/bin/claude', '/usr/local/bin/claude')\r\n }\r\n for (const candidate of [...new Set(candidates)]) {\r\n if (!isAbsolute(candidate)) continue\r\n try {\r\n await access(candidate, constants.X_OK)\r\n return candidate\r\n } catch {\r\n // Continue to the next documented candidate.\r\n }\r\n }\r\n return undefined\r\n}\r\n\r\nfunction run(executablePath: string, args: string[]) {\r\n return spawnSync(executablePath, args, {\r\n encoding: 'utf8',\r\n env: scrubbedParentEnv(),\r\n timeout: 15_000,\r\n windowsHide: true,\r\n })\r\n}\r\n\r\nasync function doctor(): Promise<number> {\r\n const configured = option('--executable') ?? process.env.DSH_CLAUDE_CODE_EXECUTABLE\r\n const path = await executable(configured)\r\n if (path === undefined) {\r\n process.stdout.write(`${JSON.stringify({\r\n executable: { status: 'missing', searched: configured === undefined ? ['claude', '~/.local/bin/claude', '/opt/homebrew/bin/claude', '/usr/local/bin/claude'] : [configured] },\r\n version: { status: 'not-run' },\r\n authentication: { status: 'not-run' },\r\n message: 'Set executablePath to an absolute Claude Code CLI path',\r\n }, null, 2)}\\n`)\r\n return 1\r\n }\r\n const versionProbe = run(path, ['--version'])\r\n const version = parseClaudeVersion(`${versionProbe.stdout ?? ''}\\n${versionProbe.stderr ?? ''}`)\r\n const authProbe = run(path, ['auth', 'status', '--json'])\r\n let authentication: Record<string, unknown> = { status: 'unknown' }\r\n if (authProbe.status === 0) {\r\n try {\r\n const value = JSON.parse(authProbe.stdout) as Record<string, unknown>\r\n authentication = {\r\n status: value.loggedIn === true ? 'signed-in' : 'signed-out',\r\n ...(typeof value.authMethod === 'string' ? { method: value.authMethod } : {}),\r\n ...(typeof value.apiProvider === 'string' ? { provider: value.apiProvider } : {}),\r\n ...(typeof value.subscriptionType === 'string' ? { subscription: value.subscriptionType } : {}),\r\n }\r\n } catch {\r\n authentication = { status: 'unknown', message: 'Authentication status was not valid JSON' }\r\n }\r\n }\r\n process.stdout.write(`${JSON.stringify({\r\n executable: { status: 'found', path },\r\n version: version === undefined ? { status: 'error' } : { status: 'ok', value: version },\r\n authentication,\r\n handshake: 'not-run',\r\n }, null, 2)}\\n`)\r\n return version === undefined ? 1 : 0\r\n}\r\n\r\nasync function main(): Promise<number> {\r\n const command = process.argv[2] ?? 'doctor'\r\n if (command === 'doctor') return doctor()\r\n if (command === 'install-preset') {\r\n process.stdout.write(`${await ensureManagedPreset()}\\n`)\r\n return 0\r\n }\r\n if (command === 'remove-preset') {\r\n process.stdout.write(`${await removeManagedPreset()}\\n`)\r\n return 0\r\n }\r\n process.stderr.write(`Usage: dsh-claude [doctor [--executable PATH] | install-preset | remove-preset]\\n`)\r\n return 2\r\n}\r\n\r\ntry {\r\n process.exitCode = await main()\r\n} catch (error) {\r\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\r\n process.exitCode = 1\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"bin.mjs","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { access } from 'node:fs/promises'\nimport { constants } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { delimiter, isAbsolute, join } from 'node:path'\nimport { spawnSync } from 'node:child_process'\nimport { scrubbedParentEnv } from '@deepseek-ai/dsh-subprocess'\nimport { parseClaudeVersion } from './executable.ts'\nimport { ensureManagedPreset, removeManagedPreset } from './preset-installer.ts'\n\nfunction option(name: string): string | undefined {\n const index = process.argv.indexOf(name)\n return index < 0 ? undefined : process.argv[index + 1]\n}\n\nasync function executable(configured?: string): Promise<string | undefined> {\n const candidates: string[] = []\n if (configured !== undefined) candidates.push(configured)\n else {\n for (const directory of (process.env.PATH ?? '').split(delimiter)) {\n if (directory.length > 0) candidates.push(join(directory, 'claude'))\n }\n candidates.push(join(homedir(), '.local', 'bin', 'claude'), '/opt/homebrew/bin/claude', '/usr/local/bin/claude')\n }\n for (const candidate of [...new Set(candidates)]) {\n if (!isAbsolute(candidate)) continue\n try {\n await access(candidate, constants.X_OK)\n return candidate\n } catch {\n // Continue to the next documented candidate.\n }\n }\n return undefined\n}\n\nfunction run(executablePath: string, args: string[]) {\n return spawnSync(executablePath, args, {\n encoding: 'utf8',\n env: scrubbedParentEnv(),\n timeout: 15_000,\n windowsHide: true,\n })\n}\n\nasync function doctor(): Promise<number> {\n const configured = option('--executable') ?? process.env.DSH_CLAUDE_CODE_EXECUTABLE\n const path = await executable(configured)\n if (path === undefined) {\n process.stdout.write(`${JSON.stringify({\n executable: { status: 'missing', searched: configured === undefined ? ['claude', '~/.local/bin/claude', '/opt/homebrew/bin/claude', '/usr/local/bin/claude'] : [configured] },\n version: { status: 'not-run' },\n authentication: { status: 'not-run' },\n message: 'Set executablePath to an absolute Claude Code CLI path',\n }, null, 2)}\\n`)\n return 1\n }\n const versionProbe = run(path, ['--version'])\n const version = parseClaudeVersion(`${versionProbe.stdout ?? ''}\\n${versionProbe.stderr ?? ''}`)\n const authProbe = run(path, ['auth', 'status', '--json'])\n let authentication: Record<string, unknown> = { status: 'unknown' }\n if (authProbe.status === 0) {\n try {\n const value = JSON.parse(authProbe.stdout) as Record<string, unknown>\n authentication = {\n status: value.loggedIn === true ? 'signed-in' : 'signed-out',\n ...(typeof value.authMethod === 'string' ? { method: value.authMethod } : {}),\n ...(typeof value.apiProvider === 'string' ? { provider: value.apiProvider } : {}),\n ...(typeof value.subscriptionType === 'string' ? { subscription: value.subscriptionType } : {}),\n }\n } catch {\n authentication = { status: 'unknown', message: 'Authentication status was not valid JSON' }\n }\n }\n process.stdout.write(`${JSON.stringify({\n executable: { status: 'found', path },\n version: version === undefined ? { status: 'error' } : { status: 'ok', value: version },\n authentication,\n handshake: 'not-run',\n }, null, 2)}\\n`)\n return version === undefined ? 1 : 0\n}\n\nasync function main(): Promise<number> {\n const command = process.argv[2] ?? 'doctor'\n if (command === 'doctor') return doctor()\n if (command === 'install-preset') {\n process.stdout.write(`${await ensureManagedPreset()}\\n`)\n return 0\n }\n if (command === 'remove-preset') {\n process.stdout.write(`${await removeManagedPreset()}\\n`)\n return 0\n }\n process.stderr.write(`Usage: dsh-claude [doctor [--executable PATH] | install-preset | remove-preset]\\n`)\n return 2\n}\n\ntry {\n process.exitCode = await main()\n} catch (error) {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\n process.exitCode = 1\n}\n"],"mappings":"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"}
package/lib/client.d.ts CHANGED
@@ -19,6 +19,9 @@ window.__ModuleLoader__.load({
19
19
  readonly tokens: "{count} tokens";
20
20
  readonly doctor: "Run Doctor";
21
21
  readonly refreshing: "Running Doctor…";
22
+ readonly diagnostics: "Runtime status";
23
+ readonly diagnosticsBody: "Check the Claude Code executable, authentication, protocol handshake, and current process configuration.";
24
+ readonly diagnosticsLoading: "Loading diagnostics…";
22
25
  readonly executable: "Executable";
23
26
  readonly version: "Version";
24
27
  readonly authentication: "Authentication";
@@ -32,6 +35,29 @@ window.__ModuleLoader__.load({
32
35
  readonly error: "Doctor failed";
33
36
  readonly security: "Permission boundary";
34
37
  readonly securityBody: "Claude tool permissions are decided through the DSH approval UI. This version does not claim kernel-level write isolation for ~/.claude or paths outside the workspace.";
38
+ readonly pluginUpdate: "Plugin updates";
39
+ readonly pluginUpdateBody: "Check npm for new releases. Only a uniquely identified npm installation can update in place; local development links are never replaced.";
40
+ readonly updateNotChecked: "Updates have not been checked yet.";
41
+ readonly installedVersion: "Installed version";
42
+ readonly latestVersion: "Latest version";
43
+ readonly installSource: "Installation source";
44
+ readonly updateStatus: "Update status";
45
+ readonly checkUpdates: "Check for updates";
46
+ readonly checkingUpdates: "Checking…";
47
+ readonly updatePlugin: "Update";
48
+ readonly updatingPlugin: "Updating…";
49
+ readonly updateError: "Update failed";
50
+ readonly restartRequired: "Restart DSH Desktop to load the updated plugin.";
51
+ readonly updateSource_registry: "npm";
52
+ readonly updateSource_link: "Local development link";
53
+ readonly updateSource_unsupported: "Unsupported source";
54
+ readonly updateSource_unknown: "Unknown";
55
+ readonly updateState_current: "Up to date";
56
+ readonly updateState_available: "Update available";
57
+ readonly updateState_linked: "Updated from the linked source checkout";
58
+ readonly updateState_unsupported: "This installation source cannot update automatically";
59
+ readonly updateState_unavailable: "The active DSH profile cannot be identified safely";
60
+ readonly updateState_error: "Check failed";
35
61
  readonly tasks: "Tasks";
36
62
  readonly tasksPanel: "Background tasks";
37
63
  readonly tasksPanelTurn: "Tasks for this run";
package/lib/client.js CHANGED
@@ -10,6 +10,8 @@ window.__ModuleLoader__.load({
10
10
  * gathering subagent activity instead of native tool cards. */
11
11
  const TASK_TOOL_NAMES = /* @__PURE__ */ new Set(["Task", "Agent"]);
12
12
  const CLAUDE_DOCTOR_PATH = "/plugins/dsh-claude/doctor";
13
+ const CLAUDE_UPDATE_CHECK_PATH = "/plugins/dsh-claude/update/check";
14
+ const CLAUDE_UPDATE_PATH = "/plugins/dsh-claude/update";
13
15
  const CLAUDE_PROJECTION_PATH = "/plugins/dsh-claude/projection";
14
16
  //#endregion
15
17
  //#region src/client/conversation-sidecar.ts
@@ -234,8 +236,28 @@ window.__ModuleLoader__.load({
234
236
  const settingsPage = {
235
237
  display: "flex",
236
238
  flexDirection: "column",
237
- gap: 18,
238
- maxWidth: 760
239
+ gap: 16,
240
+ width: "100%",
241
+ maxWidth: 820,
242
+ paddingBottom: 28
243
+ };
244
+ const settingsHero = {
245
+ display: "flex",
246
+ alignItems: "center",
247
+ gap: 14,
248
+ padding: "2px 2px 8px"
249
+ };
250
+ const settingsMark = {
251
+ width: 42,
252
+ height: 42,
253
+ display: "grid",
254
+ placeItems: "center",
255
+ flex: "none",
256
+ borderRadius: 13,
257
+ background: "var(--dsw-alias-bg-layer-2)",
258
+ color: "var(--dsw-static-blue-450)",
259
+ fontSize: 18,
260
+ fontWeight: 700
239
261
  };
240
262
  const settingsHeading = {
241
263
  margin: 0,
@@ -244,17 +266,39 @@ window.__ModuleLoader__.load({
244
266
  lineHeight: "28px",
245
267
  fontWeight: 650
246
268
  };
269
+ const settingsSectionHeading = {
270
+ margin: 0,
271
+ color: "var(--dsw-alias-label-primary)",
272
+ fontSize: 15,
273
+ lineHeight: "22px",
274
+ fontWeight: 650
275
+ };
247
276
  const settingsBody = {
248
277
  margin: 0,
249
278
  color: "var(--dsw-alias-label-secondary)",
250
- fontSize: 14,
251
- lineHeight: "22px"
279
+ fontSize: 13,
280
+ lineHeight: "20px"
281
+ };
282
+ const settingsCard = {
283
+ display: "flex",
284
+ flexDirection: "column",
285
+ gap: 14,
286
+ padding: 18,
287
+ border: "1px solid var(--dsw-alias-border-l2)",
288
+ borderRadius: 14,
289
+ background: "var(--dsw-alias-bg-layer-1)"
290
+ };
291
+ const settingsCardHeader = {
292
+ display: "flex",
293
+ alignItems: "flex-start",
294
+ justifyContent: "space-between",
295
+ gap: 16
252
296
  };
253
297
  const diagnosticGrid = {
254
298
  display: "grid",
255
- gridTemplateColumns: "minmax(130px, 0.4fr) minmax(0, 1fr)",
256
- gap: "9px 18px",
257
- padding: "16px 0",
299
+ gridTemplateColumns: "minmax(130px, 0.36fr) minmax(0, 1fr)",
300
+ gap: "10px 18px",
301
+ padding: "14px 0",
258
302
  borderTop: "1px solid var(--dsw-alias-border-l2)",
259
303
  borderBottom: "1px solid var(--dsw-alias-border-l2)",
260
304
  fontSize: 13
@@ -262,20 +306,44 @@ window.__ModuleLoader__.load({
262
306
  const diagnosticLabel = { color: "var(--dsw-alias-label-tertiary)" };
263
307
  const diagnosticValue = {
264
308
  color: "var(--dsw-alias-label-primary)",
309
+ fontWeight: 500,
265
310
  overflowWrap: "anywhere"
266
311
  };
312
+ const settingsActions = {
313
+ display: "flex",
314
+ flexWrap: "wrap",
315
+ gap: 8
316
+ };
317
+ const notice = {
318
+ margin: 0,
319
+ padding: "10px 12px",
320
+ borderRadius: 9,
321
+ background: "var(--dsw-alias-bg-layer-2)",
322
+ color: "var(--dsw-alias-label-secondary)",
323
+ fontSize: 12,
324
+ lineHeight: "18px"
325
+ };
267
326
  const button = {
268
327
  alignSelf: "flex-start",
328
+ flex: "none",
269
329
  minHeight: 34,
270
330
  padding: "6px 14px",
271
331
  border: "1px solid var(--dsw-alias-border-l2)",
272
- borderRadius: 18,
273
- background: "var(--dsw-alias-bg-layer-1)",
332
+ borderRadius: 9,
333
+ background: "var(--dsw-alias-bg-layer-2)",
274
334
  color: "var(--dsw-alias-label-primary)",
275
335
  font: "inherit",
276
336
  fontSize: 13,
337
+ fontWeight: 550,
338
+ whiteSpace: "nowrap",
277
339
  cursor: "pointer"
278
340
  };
341
+ const primaryButton = {
342
+ ...button,
343
+ borderColor: "transparent",
344
+ background: "var(--dsw-static-blue-450)",
345
+ color: "var(--dsw-static-white)"
346
+ };
279
347
  const tasksPanel = {
280
348
  display: "flex",
281
349
  flexDirection: "column",
@@ -931,6 +999,23 @@ window.__ModuleLoader__.load({
931
999
  }
932
1000
  //#endregion
933
1001
  //#region src/client/ClaudeCodeSettings.tsx
1002
+ function isPluginUpdateStatus(value) {
1003
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
1004
+ const status = value;
1005
+ return typeof status.currentVersion === "string" && (status.latestVersion === void 0 || typeof status.latestVersion === "string") && [
1006
+ "registry",
1007
+ "link",
1008
+ "unsupported",
1009
+ "unknown"
1010
+ ].includes(String(status.source)) && [
1011
+ "current",
1012
+ "available",
1013
+ "linked",
1014
+ "unsupported",
1015
+ "unavailable",
1016
+ "error"
1017
+ ].includes(String(status.state)) && typeof status.canUpdate === "boolean" && typeof status.restartRequired === "boolean" && (status.message === void 0 || typeof status.message === "string");
1018
+ }
934
1019
  function value(status, detail) {
935
1020
  return detail === void 0 ? status : `${status} · ${detail}`;
936
1021
  }
@@ -938,6 +1023,9 @@ window.__ModuleLoader__.load({
938
1023
  const [report, setReport] = useState();
939
1024
  const [error, setError] = useState();
940
1025
  const [busy, setBusy] = useState(false);
1026
+ const [updateStatus, setUpdateStatus] = useState();
1027
+ const [updateError, setUpdateError] = useState();
1028
+ const [updateBusy, setUpdateBusy] = useState();
941
1029
  const refresh = useCallback(async () => {
942
1030
  setBusy(true);
943
1031
  setError(void 0);
@@ -959,6 +1047,28 @@ window.__ModuleLoader__.load({
959
1047
  useEffect(() => {
960
1048
  refresh();
961
1049
  }, [refresh]);
1050
+ const requestUpdate = useCallback(async (action) => {
1051
+ setUpdateBusy(action);
1052
+ setUpdateError(void 0);
1053
+ try {
1054
+ const response = await fetch(action === "check" ? CLAUDE_UPDATE_CHECK_PATH : CLAUDE_UPDATE_PATH, {
1055
+ method: action === "check" ? "GET" : "POST",
1056
+ credentials: "same-origin",
1057
+ headers: { accept: "application/json" }
1058
+ });
1059
+ const payload = await response.json();
1060
+ if (!response.ok) {
1061
+ const message = typeof payload === "object" && payload !== null && "error" in payload && typeof payload.error === "string" ? payload.error : `HTTP ${response.status}`;
1062
+ throw new Error(message);
1063
+ }
1064
+ if (!isPluginUpdateStatus(payload)) throw new Error("Invalid update response");
1065
+ setUpdateStatus(payload);
1066
+ } catch (cause) {
1067
+ setUpdateError(cause instanceof Error ? cause.message : String(cause));
1068
+ } finally {
1069
+ setUpdateBusy(void 0);
1070
+ }
1071
+ }, []);
962
1072
  const rows = report === void 0 ? [] : [
963
1073
  [t("executable"), report.executable.status === "found" ? report.executable.path ?? t("unknown") : `${t("missing")} · ${report.executable.searched.join(", ")}`],
964
1074
  [t("version"), value(report.version.status, report.version.value ?? report.version.message)],
@@ -976,54 +1086,169 @@ window.__ModuleLoader__.load({
976
1086
  return /* @__PURE__ */ jsxs("div", {
977
1087
  style: settingsPage,
978
1088
  children: [
979
- /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", {
980
- style: settingsHeading,
981
- children: t("title")
982
- }), /* @__PURE__ */ jsx("p", {
983
- style: settingsBody,
984
- children: t("description")
985
- })] }),
986
- rows.length === 0 ? null : /* @__PURE__ */ jsx("div", {
987
- style: diagnosticGrid,
988
- children: rows.flatMap(([label, rowValue]) => [/* @__PURE__ */ jsx("span", {
989
- style: diagnosticLabel,
990
- children: label
991
- }, `${label}-label`), /* @__PURE__ */ jsx("span", {
992
- style: diagnosticValue,
993
- children: rowValue
994
- }, `${label}-value`)])
1089
+ /* @__PURE__ */ jsxs("header", {
1090
+ style: settingsHero,
1091
+ children: [/* @__PURE__ */ jsx("div", {
1092
+ style: settingsMark,
1093
+ "aria-hidden": "true",
1094
+ children: "C"
1095
+ }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", {
1096
+ style: settingsHeading,
1097
+ children: t("title")
1098
+ }), /* @__PURE__ */ jsx("p", {
1099
+ style: settingsBody,
1100
+ children: t("description")
1101
+ })] })]
995
1102
  }),
996
- error === void 0 ? null : /* @__PURE__ */ jsxs("p", {
997
- style: {
998
- ...settingsBody,
999
- color: "var(--dsw-alias-state-error-primary)"
1000
- },
1103
+ /* @__PURE__ */ jsxs("section", {
1104
+ style: settingsCard,
1001
1105
  children: [
1002
- t("error"),
1003
- ": ",
1004
- error
1106
+ /* @__PURE__ */ jsxs("div", {
1107
+ style: settingsCardHeader,
1108
+ children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
1109
+ style: settingsSectionHeading,
1110
+ children: t("diagnostics")
1111
+ }), /* @__PURE__ */ jsx("p", {
1112
+ style: settingsBody,
1113
+ children: t("diagnosticsBody")
1114
+ })] }), /* @__PURE__ */ jsx("button", {
1115
+ type: "button",
1116
+ style: button,
1117
+ onClick: () => {
1118
+ refresh();
1119
+ },
1120
+ disabled: busy,
1121
+ children: busy ? t("refreshing") : t("doctor")
1122
+ })]
1123
+ }),
1124
+ rows.length === 0 ? /* @__PURE__ */ jsx("p", {
1125
+ style: notice,
1126
+ children: t("diagnosticsLoading")
1127
+ }) : /* @__PURE__ */ jsx("div", {
1128
+ style: diagnosticGrid,
1129
+ children: rows.flatMap(([label, rowValue]) => [/* @__PURE__ */ jsx("span", {
1130
+ style: diagnosticLabel,
1131
+ children: label
1132
+ }, `${label}-label`), /* @__PURE__ */ jsx("span", {
1133
+ style: diagnosticValue,
1134
+ children: rowValue
1135
+ }, `${label}-value`)])
1136
+ }),
1137
+ error === void 0 ? null : /* @__PURE__ */ jsxs("p", {
1138
+ role: "alert",
1139
+ style: {
1140
+ ...notice,
1141
+ color: "var(--dsw-alias-state-error-primary)"
1142
+ },
1143
+ children: [
1144
+ t("error"),
1145
+ ": ",
1146
+ error
1147
+ ]
1148
+ })
1005
1149
  ]
1006
1150
  }),
1007
- /* @__PURE__ */ jsx("button", {
1008
- type: "button",
1009
- style: button,
1010
- onClick: () => {
1011
- refresh();
1012
- },
1013
- disabled: busy,
1014
- children: busy ? t("refreshing") : t("doctor")
1151
+ /* @__PURE__ */ jsxs("section", {
1152
+ style: settingsCard,
1153
+ children: [
1154
+ /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
1155
+ style: settingsSectionHeading,
1156
+ children: t("pluginUpdate")
1157
+ }), /* @__PURE__ */ jsx("p", {
1158
+ style: settingsBody,
1159
+ children: t("pluginUpdateBody")
1160
+ })] }),
1161
+ updateStatus === void 0 ? /* @__PURE__ */ jsx("p", {
1162
+ style: notice,
1163
+ children: t("updateNotChecked")
1164
+ }) : /* @__PURE__ */ jsxs("div", {
1165
+ style: diagnosticGrid,
1166
+ children: [
1167
+ /* @__PURE__ */ jsx("span", {
1168
+ style: diagnosticLabel,
1169
+ children: t("installedVersion")
1170
+ }),
1171
+ /* @__PURE__ */ jsx("span", {
1172
+ style: diagnosticValue,
1173
+ children: updateStatus.currentVersion
1174
+ }),
1175
+ /* @__PURE__ */ jsx("span", {
1176
+ style: diagnosticLabel,
1177
+ children: t("installSource")
1178
+ }),
1179
+ /* @__PURE__ */ jsx("span", {
1180
+ style: diagnosticValue,
1181
+ children: t(`updateSource_${updateStatus.source}`)
1182
+ }),
1183
+ /* @__PURE__ */ jsx("span", {
1184
+ style: diagnosticLabel,
1185
+ children: t("updateStatus")
1186
+ }),
1187
+ /* @__PURE__ */ jsx("span", {
1188
+ style: diagnosticValue,
1189
+ children: t(`updateState_${updateStatus.state}`)
1190
+ }),
1191
+ updateStatus.latestVersion === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1192
+ style: diagnosticLabel,
1193
+ children: t("latestVersion")
1194
+ }), /* @__PURE__ */ jsx("span", {
1195
+ style: diagnosticValue,
1196
+ children: updateStatus.latestVersion
1197
+ })] })
1198
+ ]
1199
+ }),
1200
+ updateStatus?.message === void 0 ? null : /* @__PURE__ */ jsx("p", {
1201
+ style: notice,
1202
+ children: updateStatus.message
1203
+ }),
1204
+ updateStatus?.restartRequired !== true ? null : /* @__PURE__ */ jsx("p", {
1205
+ style: notice,
1206
+ children: t("restartRequired")
1207
+ }),
1208
+ updateError === void 0 ? null : /* @__PURE__ */ jsxs("p", {
1209
+ role: "alert",
1210
+ style: {
1211
+ ...notice,
1212
+ color: "var(--dsw-alias-state-error-primary)"
1213
+ },
1214
+ children: [
1215
+ t("updateError"),
1216
+ ": ",
1217
+ updateError
1218
+ ]
1219
+ }),
1220
+ /* @__PURE__ */ jsxs("div", {
1221
+ style: settingsActions,
1222
+ children: [/* @__PURE__ */ jsx("button", {
1223
+ type: "button",
1224
+ style: button,
1225
+ onClick: () => {
1226
+ requestUpdate("check");
1227
+ },
1228
+ disabled: updateBusy !== void 0,
1229
+ children: updateBusy === "check" ? t("checkingUpdates") : t("checkUpdates")
1230
+ }), /* @__PURE__ */ jsx("button", {
1231
+ type: "button",
1232
+ style: primaryButton,
1233
+ onClick: () => {
1234
+ requestUpdate("update");
1235
+ },
1236
+ disabled: updateBusy !== void 0 || updateStatus?.canUpdate !== true,
1237
+ children: updateBusy === "update" ? t("updatingPlugin") : t("updatePlugin")
1238
+ })]
1239
+ })
1240
+ ]
1015
1241
  }),
1016
- /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
1017
- style: {
1018
- ...settingsHeading,
1019
- fontSize: 15,
1020
- lineHeight: "22px"
1021
- },
1022
- children: t("security")
1023
- }), /* @__PURE__ */ jsx("p", {
1024
- style: settingsBody,
1025
- children: t("securityBody")
1026
- })] })
1242
+ /* @__PURE__ */ jsxs("section", {
1243
+ style: settingsCard,
1244
+ children: [/* @__PURE__ */ jsx("h3", {
1245
+ style: settingsSectionHeading,
1246
+ children: t("security")
1247
+ }), /* @__PURE__ */ jsx("p", {
1248
+ style: settingsBody,
1249
+ children: t("securityBody")
1250
+ })]
1251
+ })
1027
1252
  ]
1028
1253
  });
1029
1254
  }
@@ -1151,6 +1376,9 @@ window.__ModuleLoader__.load({
1151
1376
  tokens: "{count} 个 token",
1152
1377
  doctor: "运行诊断",
1153
1378
  refreshing: "诊断中…",
1379
+ diagnostics: "运行状态",
1380
+ diagnosticsBody: "检查 Claude Code 可执行文件、登录状态、协议握手与当前进程配置。",
1381
+ diagnosticsLoading: "正在加载诊断信息…",
1154
1382
  executable: "可执行文件",
1155
1383
  version: "版本",
1156
1384
  authentication: "登录状态",
@@ -1164,6 +1392,29 @@ window.__ModuleLoader__.load({
1164
1392
  error: "诊断失败",
1165
1393
  security: "权限边界",
1166
1394
  securityBody: "Claude 工具权限通过 DSH 审批界面决定;当前版本不宣称对 ~/.claude 与工作区之外路径提供内核级写入隔离。",
1395
+ pluginUpdate: "插件更新",
1396
+ pluginUpdateBody: "检查 npm 上的新版本。只有可唯一识别的 npm 安装才能直接更新;本地开发链接不会被替换。",
1397
+ updateNotChecked: "尚未检查更新。",
1398
+ installedVersion: "已安装版本",
1399
+ latestVersion: "最新版本",
1400
+ installSource: "安装来源",
1401
+ updateStatus: "更新状态",
1402
+ checkUpdates: "检查更新",
1403
+ checkingUpdates: "检查中…",
1404
+ updatePlugin: "更新",
1405
+ updatingPlugin: "更新中…",
1406
+ updateError: "更新失败",
1407
+ restartRequired: "需要重启 DSH Desktop 才能加载更新后的插件。",
1408
+ updateSource_registry: "npm",
1409
+ updateSource_link: "本地开发链接",
1410
+ updateSource_unsupported: "不支持的来源",
1411
+ updateSource_unknown: "未知",
1412
+ updateState_current: "已是最新版本",
1413
+ updateState_available: "有可用更新",
1414
+ updateState_linked: "由链接的源码目录提供更新",
1415
+ updateState_unsupported: "此安装来源不支持自动更新",
1416
+ updateState_unavailable: "无法安全识别当前 DSH profile",
1417
+ updateState_error: "检查失败",
1167
1418
  tasks: "任务",
1168
1419
  tasksPanel: "后台任务",
1169
1420
  tasksPanelTurn: "本次执行的任务",
@@ -1203,6 +1454,9 @@ window.__ModuleLoader__.load({
1203
1454
  tokens: "{count} tokens",
1204
1455
  doctor: "Run Doctor",
1205
1456
  refreshing: "Running Doctor…",
1457
+ diagnostics: "Runtime status",
1458
+ diagnosticsBody: "Check the Claude Code executable, authentication, protocol handshake, and current process configuration.",
1459
+ diagnosticsLoading: "Loading diagnostics…",
1206
1460
  executable: "Executable",
1207
1461
  version: "Version",
1208
1462
  authentication: "Authentication",
@@ -1216,6 +1470,29 @@ window.__ModuleLoader__.load({
1216
1470
  error: "Doctor failed",
1217
1471
  security: "Permission boundary",
1218
1472
  securityBody: "Claude tool permissions are decided through the DSH approval UI. This version does not claim kernel-level write isolation for ~/.claude or paths outside the workspace.",
1473
+ pluginUpdate: "Plugin updates",
1474
+ pluginUpdateBody: "Check npm for new releases. Only a uniquely identified npm installation can update in place; local development links are never replaced.",
1475
+ updateNotChecked: "Updates have not been checked yet.",
1476
+ installedVersion: "Installed version",
1477
+ latestVersion: "Latest version",
1478
+ installSource: "Installation source",
1479
+ updateStatus: "Update status",
1480
+ checkUpdates: "Check for updates",
1481
+ checkingUpdates: "Checking…",
1482
+ updatePlugin: "Update",
1483
+ updatingPlugin: "Updating…",
1484
+ updateError: "Update failed",
1485
+ restartRequired: "Restart DSH Desktop to load the updated plugin.",
1486
+ updateSource_registry: "npm",
1487
+ updateSource_link: "Local development link",
1488
+ updateSource_unsupported: "Unsupported source",
1489
+ updateSource_unknown: "Unknown",
1490
+ updateState_current: "Up to date",
1491
+ updateState_available: "Update available",
1492
+ updateState_linked: "Updated from the linked source checkout",
1493
+ updateState_unsupported: "This installation source cannot update automatically",
1494
+ updateState_unavailable: "The active DSH profile cannot be identified safely",
1495
+ updateState_error: "Check failed",
1219
1496
  tasks: "Tasks",
1220
1497
  tasksPanel: "Background tasks",
1221
1498
  tasksPanelTurn: "Tasks for this run",