dsh-daruma 0.1.0 → 0.1.2

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
@@ -23,7 +23,9 @@ channel stays cooled-down across restarts.
23
23
  ## Install
24
24
 
25
25
  ```bash
26
- dsh plugin --profile web add github:<you>/daruma # or a published dsh-daruma
26
+ dsh plugin --profile web add dsh-daruma # from npm
27
+ # or from a checkout:
28
+ dsh plugin --profile web add link:./packages/daruma-core link:./packages/dsh-daruma
27
29
  ```
28
30
 
29
31
  ## Configure
@@ -60,8 +60,8 @@ const candidateRowStyle = {
60
60
  };
61
61
  /** One candidate row, memoized so selection changes only re-render it. */
62
62
  const CandidateRow = memo(function CandidateRow(props) {
63
- const { candidate, isBackup, t, onSetBackup } = props;
64
- return (_jsxs("div", { style: candidateRowStyle, children: [_jsx("span", { style: { width: 14, flexShrink: 0 } }), _jsx("span", { style: { flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: candidate.model }), isBackup && _jsx(Pill, { active: true, children: t('currentBackupMark') }), _jsx(Button, { size: "sm", variant: "ghost", disabled: isBackup, onClick: () => onSetBackup(candidate.model), children: t('setBackup') })] }));
63
+ const { candidate, isBackup, busy, t, onSetBackup } = props;
64
+ return (_jsxs("div", { style: candidateRowStyle, children: [_jsx("span", { style: { width: 14, flexShrink: 0 } }), _jsx("span", { style: { flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: candidate.model }), isBackup && _jsx(Pill, { active: true, children: t('currentBackupMark') }), _jsx(Button, { size: "sm", variant: "ghost", disabled: isBackup || busy, onClick: () => onSetBackup(candidate.model), children: t('setBackup') })] }));
65
65
  });
66
66
  export function BackupPanel(props) {
67
67
  const { api, t, status, onClose } = props;
@@ -116,6 +116,7 @@ export function BackupPanel(props) {
116
116
  }
117
117
  };
118
118
  const clearBackup = async () => {
119
+ setBusy('__clear__');
119
120
  setError(null);
120
121
  try {
121
122
  await api.clearBackup();
@@ -124,9 +125,12 @@ export function BackupPanel(props) {
124
125
  catch (cause) {
125
126
  setError(cause instanceof Error ? cause.message : String(cause));
126
127
  }
128
+ finally {
129
+ setBusy(null);
130
+ }
127
131
  };
128
132
  // Stable callback so memoized CandidateRow props don't change every render.
129
133
  const handleSetBackup = useCallback((model) => void setBackup(model), [provider]);
130
- return (_jsx(Modal, { open: true, onClose: onClose, title: t('backupManage'), className: "daruma-wide-dialog", closeLabel: t('close'), description: t('backupManageHint'), footer: _jsx(Button, { variant: "primary", onClick: onClose, children: t('close') }), children: _jsxs("div", { style: sectionStyle, children: [status !== null && status.failoverCount > 0 && (_jsxs("div", { style: noteStyle, children: [t('failoverCount'), ": ", status.failoverCount, status.failoverHistory.length > 0 && (_jsxs(_Fragment, { children: [' · ', t('lastFailover'), ": ", status.failoverHistory.map((h) => `${h.from} → ${h.to}`).join(' · ')] }))] })), backupShown !== null && (_jsxs("div", { style: rowStyle, children: [_jsxs("span", { style: { flexShrink: 0 }, children: [t('currentBackup'), ":"] }), _jsx(Pill, { active: true, style: backupPillStyle, title: `${backupShown.provider}/${backupShown.model}`, children: _jsxs("span", { style: ellipsisStyle, children: [backupShown.provider, "/", backupShown.model] }) }), _jsx(Button, { size: "sm", variant: "ghost", style: { flexShrink: 0 }, onClick: () => void clearBackup(), children: t('clearBackup') })] })), _jsxs("div", { style: rowStyle, children: [(status?.providers ?? []).length > 0 ? (_jsx("select", { value: provider, disabled: loading, onChange: (event) => setProvider(event.currentTarget.value), style: { flex: 1, padding: '4px 8px', fontSize: 13 }, children: status?.providers.map((name) => (_jsx("option", { value: name, children: name }, name))) })) : (_jsx("input", { value: provider, placeholder: t('providerPlaceholder'), onChange: (event) => setProvider(event.currentTarget.value), style: { flex: 1, padding: '4px 8px', fontSize: 13 } })), _jsx(Button, { size: "sm", variant: "outline", onClick: () => void loadCandidates(), disabled: provider === '' || loading, children: loading ? t('loading') : t('loadCandidates') })] }), error !== null && _jsx("div", { style: { color: 'var(--dsw-text-danger, #e5484d)' }, children: error }), candidates !== null && (_jsxs(_Fragment, { children: [_jsx("div", { style: rowStyle, children: _jsxs("span", { children: [t('candidates'), " (", candidates.length, ")"] }) }), candidates.length === 0 && _jsx("div", { style: noteStyle, children: t('noCandidates') }), _jsx("div", { style: listStyle, children: candidates.map((candidate) => (_jsx(CandidateRow, { candidate: candidate, isBackup: candidate.model === backupModel, t: t, onSetBackup: handleSetBackup }, candidate.model))) })] }))] }) }));
134
+ return (_jsx(Modal, { open: true, onClose: onClose, title: t('backupManage'), className: "daruma-wide-dialog", closeLabel: t('close'), description: t('backupManageHint'), footer: _jsx(Button, { variant: "primary", onClick: onClose, children: t('close') }), children: _jsxs("div", { style: sectionStyle, children: [status !== null && status.failoverCount > 0 && (_jsxs("div", { style: noteStyle, children: [t('failoverCount'), ": ", status.failoverCount, status.failoverHistory.length > 0 && (_jsxs(_Fragment, { children: [' · ', t('lastFailover'), ": ", status.failoverHistory.map((h) => `${h.from} → ${h.to}`).join(' · ')] }))] })), backupShown !== null && (_jsxs("div", { style: rowStyle, children: [_jsxs("span", { style: { flexShrink: 0 }, children: [t('currentBackup'), ":"] }), _jsx(Pill, { active: true, style: backupPillStyle, title: `${backupShown.provider}/${backupShown.model}`, children: _jsxs("span", { style: ellipsisStyle, children: [backupShown.provider, "/", backupShown.model] }) }), _jsx(Button, { size: "sm", variant: "ghost", style: { flexShrink: 0 }, disabled: busy !== null, onClick: () => void clearBackup(), children: t('clearBackup') })] })), _jsxs("div", { style: rowStyle, children: [(status?.providers ?? []).length > 0 ? (_jsx("select", { value: provider, disabled: loading, onChange: (event) => setProvider(event.currentTarget.value), style: { flex: 1, padding: '4px 8px', fontSize: 13 }, children: status?.providers.map((name) => (_jsx("option", { value: name, children: name }, name))) })) : (_jsx("input", { value: provider, placeholder: t('providerPlaceholder'), onChange: (event) => setProvider(event.currentTarget.value), style: { flex: 1, padding: '4px 8px', fontSize: 13 } })), _jsx(Button, { size: "sm", variant: "outline", onClick: () => void loadCandidates(), disabled: provider === '' || loading, children: loading ? t('loading') : t('loadCandidates') })] }), error !== null && _jsx("div", { style: { color: 'var(--dsw-text-danger, #e5484d)' }, children: error }), candidates !== null && (_jsxs(_Fragment, { children: [_jsx("div", { style: rowStyle, children: _jsxs("span", { children: [t('candidates'), " (", candidates.length, ")"] }) }), candidates.length === 0 && _jsx("div", { style: noteStyle, children: t('noCandidates') }), _jsx("div", { style: listStyle, children: candidates.map((candidate) => (_jsx(CandidateRow, { candidate: candidate, isBackup: candidate.model === backupModel, busy: busy !== null, t: t, onSetBackup: handleSetBackup }, candidate.model))) })] }))] }) }));
131
135
  }
132
136
  //# sourceMappingURL=BackupPanel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BackupPanel.js","sourceRoot":"","sources":["../../src/client/BackupPanel.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BackupPanel.js","sourceRoot":"","sources":["../../src/client/BackupPanel.tsx"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
6
6
  */
7
7
  import { useCallback, useEffect, useState } from 'react';
8
8
  import { Button, IconCheckOutline16, IconWarningOutline16 } from '@deepseek-ai/dsh-client-ui-primitives';
9
+ import { overallState } from "./health.js";
9
10
  import { BackupPanel } from "./BackupPanel.js";
10
11
  const controlStyle = {
11
12
  display: 'inline-flex',
@@ -16,16 +17,6 @@ const controlStyle = {
16
17
  textOverflow: 'ellipsis',
17
18
  whiteSpace: 'nowrap',
18
19
  };
19
- /** Overall health: any cooling channel → error, any probe → warning, else done. */
20
- function overallState(status) {
21
- if (status === null)
22
- return 'ongoing';
23
- if (status.channels.some((c) => c.state === 'COOLDOWN'))
24
- return 'error';
25
- if (status.channels.some((c) => c.state === 'PROBE'))
26
- return 'warning';
27
- return 'done';
28
- }
29
20
  const iconColor = {
30
21
  done: 'var(--dsw-text-success, #30a46c)',
31
22
  warning: 'var(--dsw-text-warning, #f5a524)',
@@ -59,7 +50,7 @@ export function StatusDock(props) {
59
50
  const backupLabel = status?.backup !== null && status?.backup !== undefined
60
51
  ? `${status.backup.provider}/${status.backup.model}`
61
52
  : t('backupNone');
62
- return (_jsxs(_Fragment, { children: [_jsxs(Button, { size: "sm", variant: "ghost", title: t('backupManageHint'), onClick: () => setPanelOpen(true), style: controlStyle, children: [_jsx(StatusIcon, { state: overallState(status) }), _jsxs("span", { style: { minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: [t('backup'), ": ", backupLabel] })] }), panelOpen && (_jsx(BackupPanel, { api: props.api, t: t, status: status, onClose: () => {
53
+ return (_jsxs(_Fragment, { children: [_jsxs(Button, { size: "sm", variant: "ghost", title: t('backupManageHint'), onClick: () => setPanelOpen(true), style: controlStyle, children: [_jsx(StatusIcon, { state: overallState(status?.channels ?? null, Date.now()) }), _jsxs("span", { style: { minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: [t('backup'), ": ", backupLabel] })] }), panelOpen && (_jsx(BackupPanel, { api: props.api, t: t, status: status, onClose: () => {
63
54
  setPanelOpen(false);
64
55
  void load();
65
56
  } }))] }));
@@ -1 +1 @@
1
- {"version":3,"file":"StatusDock.js","sourceRoot":"","sources":["../../src/client/StatusDock.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"StatusDock.js","sourceRoot":"","sources":["../../src/client/StatusDock.tsx"],"names":[],"mappings":"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"}
@@ -7,6 +7,8 @@ export interface ChannelHealthView {
7
7
  channel: string;
8
8
  state: ChannelState;
9
9
  failures: number;
10
+ /** Epoch ms when the channel's cooldown ends; `0` when not cooling. */
11
+ cooldownUntilMs: number;
10
12
  }
11
13
  export interface StatusView {
12
14
  current: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/client/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAwCH,MAAM,UAAU,SAAS,CAAC,GAAQ;IAChC,MAAM,IAAI,GAAG,KAAK,EAAK,QAAgB,EAAE,OAAiB,EAAc,EAAE;QACxE,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAiB,CAAA;QAC7D,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,cAAc,QAAQ,SAAS,CAAC,CAAA;QAC3E,CAAC;QACD,OAAO,MAAM,CAAC,KAAU,CAAA;IAC1B,CAAC,CAAA;IAED,OAAO;QACL,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAa,QAAQ,CAAC;QACxC,cAAc,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAkB,gBAAgB,EAAE,EAAE,QAAQ,EAAE,CAAC;QACnF,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;YACnC,MAAM,IAAI,CAAkB,WAAW,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QAC/D,CAAC;QACD,WAAW,EAAE,KAAK,IAAI,EAAE;YACtB,MAAM,IAAI,CAAkB,aAAa,CAAC,CAAA;QAC5C,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/client/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA0CH,MAAM,UAAU,SAAS,CAAC,GAAQ;IAChC,MAAM,IAAI,GAAG,KAAK,EAAK,QAAgB,EAAE,OAAiB,EAAc,EAAE;QACxE,MAAM,MAAM,GAAG,CAAC,MAAM,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAiB,CAAA;QAC7D,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,cAAc,QAAQ,SAAS,CAAC,CAAA;QAC3E,CAAC;QACD,OAAO,MAAM,CAAC,KAAU,CAAA;IAC1B,CAAC,CAAA;IAED,OAAO;QACL,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAa,QAAQ,CAAC;QACxC,cAAc,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAkB,gBAAgB,EAAE,EAAE,QAAQ,EAAE,CAAC;QACnF,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;YACnC,MAAM,IAAI,CAAkB,WAAW,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QAC/D,CAAC;QACD,WAAW,EAAE,KAAK,IAAI,EAAE;YACtB,MAAM,IAAI,CAAkB,aAAa,CAAC,CAAA;QAC5C,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Time-aware channel-health classification for the status dock.
3
+ *
4
+ * The host exposes no request-success event, so a channel whose cooldown has
5
+ * expired keeps its `COOLDOWN` state field forever — it becomes routable again
6
+ * (`canRouteNow`) without ever flipping back to `HEALTHY`. The dock therefore
7
+ * must judge by time, not by the raw state field: only a channel that is
8
+ * *still* cooling (cooldown not yet expired) counts as an error.
9
+ */
10
+ import type { ChannelHealthView } from './api.ts';
11
+ export type Dot = 'done' | 'warning' | 'ongoing' | 'error';
12
+ /**
13
+ * Overall dock state:
14
+ * - `error` — at least one channel is still cooling (`cooldownUntilMs > now`).
15
+ * - `warning` — a probe is in flight (kept for parity; the adapter no longer
16
+ * enters PROBE, but persisted legacy states may surface it).
17
+ * - `done` — everything routable: healthy, or cooled down long enough.
18
+ * - `ongoing` — no snapshot yet.
19
+ */
20
+ export declare function overallState(channels: readonly ChannelHealthView[] | null, nowMs: number): Dot;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Time-aware channel-health classification for the status dock.
3
+ *
4
+ * The host exposes no request-success event, so a channel whose cooldown has
5
+ * expired keeps its `COOLDOWN` state field forever — it becomes routable again
6
+ * (`canRouteNow`) without ever flipping back to `HEALTHY`. The dock therefore
7
+ * must judge by time, not by the raw state field: only a channel that is
8
+ * *still* cooling (cooldown not yet expired) counts as an error.
9
+ */
10
+ /**
11
+ * Overall dock state:
12
+ * - `error` — at least one channel is still cooling (`cooldownUntilMs > now`).
13
+ * - `warning` — a probe is in flight (kept for parity; the adapter no longer
14
+ * enters PROBE, but persisted legacy states may surface it).
15
+ * - `done` — everything routable: healthy, or cooled down long enough.
16
+ * - `ongoing` — no snapshot yet.
17
+ */
18
+ export function overallState(channels, nowMs) {
19
+ if (channels === null)
20
+ return 'ongoing';
21
+ if (channels.some((c) => c.state === 'COOLDOWN' && c.cooldownUntilMs > nowMs))
22
+ return 'error';
23
+ if (channels.some((c) => c.state === 'PROBE'))
24
+ return 'warning';
25
+ return 'done';
26
+ }
27
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/client/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,QAA6C,EAC7C,KAAa;IAEb,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,SAAS,CAAA;IACvC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,UAAU,IAAI,CAAC,CAAC,eAAe,GAAG,KAAK,CAAC;QAAE,OAAO,OAAO,CAAA;IAC7F,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC;QAAE,OAAO,SAAS,CAAA;IAC/D,OAAO,MAAM,CAAA;AACf,CAAC"}
package/lib/client.js CHANGED
@@ -88,6 +88,31 @@ window.__ModuleLoader__.load({
88
88
  };
89
89
  }
90
90
  //#endregion
91
+ //#region lib/client/health.js
92
+ /**
93
+ * Time-aware channel-health classification for the status dock.
94
+ *
95
+ * The host exposes no request-success event, so a channel whose cooldown has
96
+ * expired keeps its `COOLDOWN` state field forever — it becomes routable again
97
+ * (`canRouteNow`) without ever flipping back to `HEALTHY`. The dock therefore
98
+ * must judge by time, not by the raw state field: only a channel that is
99
+ * *still* cooling (cooldown not yet expired) counts as an error.
100
+ */
101
+ /**
102
+ * Overall dock state:
103
+ * - `error` — at least one channel is still cooling (`cooldownUntilMs > now`).
104
+ * - `warning` — a probe is in flight (kept for parity; the adapter no longer
105
+ * enters PROBE, but persisted legacy states may surface it).
106
+ * - `done` — everything routable: healthy, or cooled down long enough.
107
+ * - `ongoing` — no snapshot yet.
108
+ */
109
+ function overallState(channels, nowMs) {
110
+ if (channels === null) return "ongoing";
111
+ if (channels.some((c) => c.state === "COOLDOWN" && c.cooldownUntilMs > nowMs)) return "error";
112
+ if (channels.some((c) => c.state === "PROBE")) return "warning";
113
+ return "done";
114
+ }
115
+ //#endregion
91
116
  //#region lib/client/BackupPanel.js
92
117
  /**
93
118
  * BackupChannelPanel: list candidate models for a provider and pick one as
@@ -148,7 +173,7 @@ window.__ModuleLoader__.load({
148
173
  };
149
174
  /** One candidate row, memoized so selection changes only re-render it. */
150
175
  const CandidateRow = (0, react.memo)(function CandidateRow(props) {
151
- const { candidate, isBackup, t, onSetBackup } = props;
176
+ const { candidate, isBackup, busy, t, onSetBackup } = props;
152
177
  return (0, react_jsx_runtime.jsxs)("div", {
153
178
  style: candidateRowStyle,
154
179
  children: [
@@ -173,7 +198,7 @@ window.__ModuleLoader__.load({
173
198
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
174
199
  size: "sm",
175
200
  variant: "ghost",
176
- disabled: isBackup,
201
+ disabled: isBackup || busy,
177
202
  onClick: () => onSetBackup(candidate.model),
178
203
  children: t("setBackup")
179
204
  })
@@ -224,12 +249,15 @@ window.__ModuleLoader__.load({
224
249
  }
225
250
  };
226
251
  const clearBackup = async () => {
252
+ setBusy("__clear__");
227
253
  setError(null);
228
254
  try {
229
255
  await api.clearBackup();
230
256
  setBackupOverride(null);
231
257
  } catch (cause) {
232
258
  setError(cause instanceof Error ? cause.message : String(cause));
259
+ } finally {
260
+ setBusy(null);
233
261
  }
234
262
  };
235
263
  const handleSetBackup = (0, react.useCallback)((model) => void setBackup(model), [provider]);
@@ -286,6 +314,7 @@ window.__ModuleLoader__.load({
286
314
  size: "sm",
287
315
  variant: "ghost",
288
316
  style: { flexShrink: 0 },
317
+ disabled: busy !== null,
289
318
  onClick: () => void clearBackup(),
290
319
  children: t("clearBackup")
291
320
  })
@@ -346,6 +375,7 @@ window.__ModuleLoader__.load({
346
375
  children: candidates.map((candidate) => (0, react_jsx_runtime.jsx)(CandidateRow, {
347
376
  candidate,
348
377
  isBackup: candidate.model === backupModel,
378
+ busy: busy !== null,
349
379
  t,
350
380
  onSetBackup: handleSetBackup
351
381
  }, candidate.model))
@@ -371,13 +401,6 @@ window.__ModuleLoader__.load({
371
401
  textOverflow: "ellipsis",
372
402
  whiteSpace: "nowrap"
373
403
  };
374
- /** Overall health: any cooling channel → error, any probe → warning, else done. */
375
- function overallState(status) {
376
- if (status === null) return "ongoing";
377
- if (status.channels.some((c) => c.state === "COOLDOWN")) return "error";
378
- if (status.channels.some((c) => c.state === "PROBE")) return "warning";
379
- return "done";
380
- }
381
404
  const iconColor = {
382
405
  done: "var(--dsw-text-success, #30a46c)",
383
406
  warning: "var(--dsw-text-warning, #f5a524)",
@@ -417,7 +440,7 @@ window.__ModuleLoader__.load({
417
440
  title: t("backupManageHint"),
418
441
  onClick: () => setPanelOpen(true),
419
442
  style: controlStyle,
420
- children: [(0, react_jsx_runtime.jsx)(StatusIcon, { state: overallState(status) }), (0, react_jsx_runtime.jsxs)("span", {
443
+ children: [(0, react_jsx_runtime.jsx)(StatusIcon, { state: overallState(status?.channels ?? null, Date.now()) }), (0, react_jsx_runtime.jsxs)("span", {
421
444
  style: {
422
445
  minWidth: 0,
423
446
  overflow: "hidden",
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["memo","_jsxs","_jsx","Pill","Button","useState","useMemo","useCallback","Modal","_Fragment","_jsx","IconCheckOutline16","IconWarningOutline16","useState","useCallback","_jsxs","_Fragment","Button","h"],"sources":["client/locales.js","client/api.js","client/BackupPanel.js","client/StatusDock.js","client/index.js"],"sourcesContent":["/** zh/en dictionaries for the daruma client UI. */\nexport const zh = {\n status: '渠道状态',\n current: '当前',\n backup: '备用',\n backupNone: '未设置',\n backupManage: '备用渠道',\n backupManageHint: '从候选列表选择备用渠道',\n failoverCount: '已切换',\n lastFailover: '上次切换',\n healthy: '健康',\n cooldown: '冷却中',\n probe: '探测中',\n refresh: '刷新',\n close: '关闭',\n clearBackup: '清除备用',\n provider: '提供方',\n providerPlaceholder: 'provider,如 mt',\n loadCandidates: '加载候选',\n loading: '加载中…',\n candidates: '候选模型',\n setBackup: '设为备用',\n currentBackup: '当前备用',\n currentBackupMark: '备用',\n noCandidates: '未加载到候选模型',\n empty: '暂无渠道数据',\n};\nexport const en = {\n status: 'Channel status',\n current: 'Current',\n backup: 'Backup',\n backupNone: 'none',\n backupManage: 'Backup channel',\n backupManageHint: 'Pick a backup channel from the candidate list',\n failoverCount: 'failovers',\n lastFailover: 'last failover',\n healthy: 'healthy',\n cooldown: 'cooling',\n probe: 'probing',\n refresh: 'Refresh',\n close: 'Close',\n clearBackup: 'Clear backup',\n provider: 'Provider',\n providerPlaceholder: 'provider, e.g. mt',\n loadCandidates: 'Load candidates',\n loading: 'Loading…',\n candidates: 'Candidate models',\n setBackup: 'Set as backup',\n currentBackup: 'Current backup',\n currentBackupMark: 'backup',\n noCandidates: 'No candidates loaded',\n empty: 'No channel data yet',\n};\n//# sourceMappingURL=locales.js.map","/**\n * Client-side wire types and RPC wrapper for the `/dsh-daruma` channel.\n * Structural types only — no monorepo-internal imports.\n */\nexport function createApi(rpc) {\n const call = async (endpoint, payload) => {\n const result = (await rpc(endpoint, payload));\n if (!result.ok) {\n throw new Error(result.error?.message ?? `daruma rpc ${endpoint} failed`);\n }\n return result.value;\n };\n return {\n status: () => call('status'),\n listCandidates: (provider) => call('listCandidates', { provider }),\n setBackup: async (provider, model) => {\n await call('setBackup', { provider, model });\n },\n clearBackup: async () => {\n await call('clearBackup');\n },\n };\n}\n//# sourceMappingURL=api.js.map","import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\n/**\n * BackupChannelPanel: list candidate models for a provider and pick one as\n * the failover backup. Rendered inside a primitives Modal.\n *\n * No probing happens here anymore — the panel is a plain picker. Channel\n * health still updates from real traffic via the recovery engine.\n */\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\nimport { Button, Modal, Pill, } from '@deepseek-ai/dsh-client-ui-primitives';\nfunction deriveProvider(status) {\n if (status === null)\n return '';\n if (status.current !== null)\n return status.current.split('::')[0] ?? '';\n if (status.backup !== null)\n return status.backup.provider;\n return status.providers[0] ?? '';\n}\nconst sectionStyle = {\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n padding: '12px 0',\n fontSize: '13px',\n};\nconst rowStyle = {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n};\nconst noteStyle = { color: 'var(--dsw-text-tertiary, #999)', fontSize: '12px' };\n/** Clamp a long provider/model name so the row never wraps. */\nconst backupPillStyle = {\n flex: '1 1 auto',\n minWidth: 0,\n overflow: 'hidden',\n};\nconst ellipsisStyle = {\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n};\nconst listStyle = {\n maxHeight: 300,\n overflowY: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n contain: 'content',\n willChange: 'scroll-position',\n overscrollBehavior: 'contain',\n};\n/** Skip rendering rows outside the viewport while scrolling. */\nconst candidateRowStyle = {\n ...rowStyle,\n contentVisibility: 'auto',\n containIntrinsicSize: '28px',\n};\n/** One candidate row, memoized so selection changes only re-render it. */\nconst CandidateRow = memo(function CandidateRow(props) {\n const { candidate, isBackup, t, onSetBackup } = props;\n return (_jsxs(\"div\", { style: candidateRowStyle, children: [_jsx(\"span\", { style: { width: 14, flexShrink: 0 } }), _jsx(\"span\", { style: { flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: candidate.model }), isBackup && _jsx(Pill, { active: true, children: t('currentBackupMark') }), _jsx(Button, { size: \"sm\", variant: \"ghost\", disabled: isBackup, onClick: () => onSetBackup(candidate.model), children: t('setBackup') })] }));\n});\nexport function BackupPanel(props) {\n const { api, t, status, onClose } = props;\n const [provider, setProvider] = useState(deriveProvider(status));\n const [candidates, setCandidates] = useState(null);\n const [loading, setLoading] = useState(false);\n const [busy, setBusy] = useState(null);\n const [error, setError] = useState(null);\n // Local overlay on the status-prop backup: applied optimistically after\n // set/clear so the row reflects the change without waiting for the parent\n // to re-fetch status. Cleared whenever a fresh status arrives.\n const [backupOverride, setBackupOverride] = useState(undefined);\n // The effective backup shown in the panel: local override → status prop.\n const backupShown = backupOverride !== undefined ? backupOverride : status?.backup ?? null;\n // O(1) lookup for the current backup model; re-built only when the effective backup changes.\n const backupModel = useMemo(() => (backupShown !== null && backupShown.provider === provider ? backupShown.model : null), [backupShown, provider]);\n const loadCandidates = async () => {\n if (provider === '')\n return;\n setLoading(true);\n setError(null);\n try {\n setCandidates(await api.listCandidates(provider));\n }\n catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause));\n }\n finally {\n setLoading(false);\n }\n };\n useEffect(() => {\n if (provider !== '')\n void loadCandidates();\n }, [provider]);\n // A fresh status from the parent supersedes the local override.\n useEffect(() => {\n setBackupOverride(undefined);\n }, [status]);\n const setBackup = async (model) => {\n setBusy(model);\n setError(null);\n try {\n await api.setBackup(provider, model);\n setBackupOverride({ provider, model });\n }\n catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause));\n }\n finally {\n setBusy(null);\n }\n };\n const clearBackup = async () => {\n setError(null);\n try {\n await api.clearBackup();\n setBackupOverride(null);\n }\n catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause));\n }\n };\n // Stable callback so memoized CandidateRow props don't change every render.\n const handleSetBackup = useCallback((model) => void setBackup(model), [provider]);\n return (_jsx(Modal, { open: true, onClose: onClose, title: t('backupManage'), className: \"daruma-wide-dialog\", closeLabel: t('close'), description: t('backupManageHint'), footer: _jsx(Button, { variant: \"primary\", onClick: onClose, children: t('close') }), children: _jsxs(\"div\", { style: sectionStyle, children: [status !== null && status.failoverCount > 0 && (_jsxs(\"div\", { style: noteStyle, children: [t('failoverCount'), \": \", status.failoverCount, status.failoverHistory.length > 0 && (_jsxs(_Fragment, { children: [' · ', t('lastFailover'), \": \", status.failoverHistory.map((h) => `${h.from} → ${h.to}`).join(' · ')] }))] })), backupShown !== null && (_jsxs(\"div\", { style: rowStyle, children: [_jsxs(\"span\", { style: { flexShrink: 0 }, children: [t('currentBackup'), \":\"] }), _jsx(Pill, { active: true, style: backupPillStyle, title: `${backupShown.provider}/${backupShown.model}`, children: _jsxs(\"span\", { style: ellipsisStyle, children: [backupShown.provider, \"/\", backupShown.model] }) }), _jsx(Button, { size: \"sm\", variant: \"ghost\", style: { flexShrink: 0 }, onClick: () => void clearBackup(), children: t('clearBackup') })] })), _jsxs(\"div\", { style: rowStyle, children: [(status?.providers ?? []).length > 0 ? (_jsx(\"select\", { value: provider, disabled: loading, onChange: (event) => setProvider(event.currentTarget.value), style: { flex: 1, padding: '4px 8px', fontSize: 13 }, children: status?.providers.map((name) => (_jsx(\"option\", { value: name, children: name }, name))) })) : (_jsx(\"input\", { value: provider, placeholder: t('providerPlaceholder'), onChange: (event) => setProvider(event.currentTarget.value), style: { flex: 1, padding: '4px 8px', fontSize: 13 } })), _jsx(Button, { size: \"sm\", variant: \"outline\", onClick: () => void loadCandidates(), disabled: provider === '' || loading, children: loading ? t('loading') : t('loadCandidates') })] }), error !== null && _jsx(\"div\", { style: { color: 'var(--dsw-text-danger, #e5484d)' }, children: error }), candidates !== null && (_jsxs(_Fragment, { children: [_jsx(\"div\", { style: rowStyle, children: _jsxs(\"span\", { children: [t('candidates'), \" (\", candidates.length, \")\"] }) }), candidates.length === 0 && _jsx(\"div\", { style: noteStyle, children: t('noCandidates') }), _jsx(\"div\", { style: listStyle, children: candidates.map((candidate) => (_jsx(CandidateRow, { candidate: candidate, isBackup: candidate.model === backupModel, t: t, onSetBackup: handleSetBackup }, candidate.model))) })] }))] }) }));\n}\n//# sourceMappingURL=BackupPanel.js.map","import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\n/**\n * DarumaStatus: a compact control at the right end of the composer tool row,\n * next to the model selector. Shows overall channel health and the backup\n * selection; clicking it opens the backup-channel panel.\n */\nimport { useCallback, useEffect, useState } from 'react';\nimport { Button, IconCheckOutline16, IconWarningOutline16 } from '@deepseek-ai/dsh-client-ui-primitives';\nimport { BackupPanel } from \"./BackupPanel.js\";\nconst controlStyle = {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 6,\n maxWidth: 220,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n};\n/** Overall health: any cooling channel → error, any probe → warning, else done. */\nfunction overallState(status) {\n if (status === null)\n return 'ongoing';\n if (status.channels.some((c) => c.state === 'COOLDOWN'))\n return 'error';\n if (status.channels.some((c) => c.state === 'PROBE'))\n return 'warning';\n return 'done';\n}\nconst iconColor = {\n done: 'var(--dsw-text-success, #30a46c)',\n warning: 'var(--dsw-text-warning, #f5a524)',\n error: 'var(--dsw-text-danger, #e5484d)',\n ongoing: 'var(--dsw-text-secondary, #888)',\n};\n/** Status glyph: a check when healthy, a warning otherwise. */\nfunction StatusIcon(props) {\n return (_jsx(\"span\", { style: { display: 'inline-flex', color: iconColor[props.state], flexShrink: 0 }, children: props.state === 'done'\n ? _jsx(IconCheckOutline16, { size: 14 })\n : _jsx(IconWarningOutline16, { size: 14 }) }));\n}\nexport function StatusDock(props) {\n const [status, setStatus] = useState(null);\n const [panelOpen, setPanelOpen] = useState(false);\n const load = useCallback(async () => {\n try {\n const value = await props.api.status();\n setStatus(value);\n }\n catch {\n // keep last good snapshot; the control stays quiet on RPC failure\n }\n }, [props.api]);\n useEffect(() => {\n void load();\n const timer = setInterval(() => void load(), 30_000);\n return () => clearInterval(timer);\n }, [load]);\n const t = props.t;\n const backupLabel = status?.backup !== null && status?.backup !== undefined\n ? `${status.backup.provider}/${status.backup.model}`\n : t('backupNone');\n return (_jsxs(_Fragment, { children: [_jsxs(Button, { size: \"sm\", variant: \"ghost\", title: t('backupManageHint'), onClick: () => setPanelOpen(true), style: controlStyle, children: [_jsx(StatusIcon, { state: overallState(status) }), _jsxs(\"span\", { style: { minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: [t('backup'), \": \", backupLabel] })] }), panelOpen && (_jsx(BackupPanel, { api: props.api, t: t, status: status, onClose: () => {\n setPanelOpen(false);\n void load();\n } }))] }));\n}\n//# sourceMappingURL=StatusDock.js.map","/**\n * dsh-daruma client: registers a compact channel-status dock above the\n * composer (conversation.input.dock) with a \"backup channel\" panel that\n * lists candidate models and picks a backup. Built by tsdown into the\n * __ModuleLoader__ factory bundle at lib/client.js.\n */\nimport { createElement as h } from 'react';\nimport { en, zh } from \"./locales.js\";\nimport { createApi } from \"./api.js\";\nimport { StatusDock } from \"./StatusDock.js\";\nconst NS = 'daruma';\nexport const name = 'dsh-daruma';\nexport const inject = ['slots', 'locale'];\nexport function apply(ctx) {\n // Widen the backup-panel dialog: the primitives Modal card is fixed at\n // min(380px, 100%), which truncates long provider/model names. A global\n // class (not a CSS module) outranks the module-scoped `.dialog` rule.\n if (typeof document !== 'undefined') {\n const tagId = 'daruma-panel-style';\n if (document.querySelector(`style[data-daruma=\"${tagId}\"]`) === null) {\n const style = document.createElement('style');\n style.dataset.daruma = tagId;\n style.textContent = '.daruma-wide-dialog.daruma-wide-dialog { width: min(560px, 100%); }';\n document.head.appendChild(style);\n }\n }\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-daruma: dictionaries');\n const t = ctx.locale.bind(NS);\n const connection = ctx.get('connection');\n if (connection === undefined) {\n console.warn('[dsh-daruma] web transport unavailable — client UI disabled');\n return;\n }\n const rpc = (endpoint, payload) => connection.rpc.call('/dsh-daruma', endpoint, payload ?? {});\n const api = createApi(rpc);\n ctx.slots.inject('conversation.input.right', () => ctx.slots.register({\n name: 'conversation.input.right',\n id: 'daruma-status',\n order: 0,\n inject: () => ({ api, t }),\n }, () => h(StatusDock, { api, t })));\n}\n//# sourceMappingURL=index.js.map"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["memo","_jsxs","_jsx","Pill","Button","useState","useMemo","useCallback","Modal","_Fragment","_jsx","IconCheckOutline16","IconWarningOutline16","useState","useCallback","_jsxs","_Fragment","Button","h"],"sources":["client/locales.js","client/api.js","client/health.js","client/BackupPanel.js","client/StatusDock.js","client/index.js"],"sourcesContent":["/** zh/en dictionaries for the daruma client UI. */\nexport const zh = {\n status: '渠道状态',\n current: '当前',\n backup: '备用',\n backupNone: '未设置',\n backupManage: '备用渠道',\n backupManageHint: '从候选列表选择备用渠道',\n failoverCount: '已切换',\n lastFailover: '上次切换',\n healthy: '健康',\n cooldown: '冷却中',\n probe: '探测中',\n refresh: '刷新',\n close: '关闭',\n clearBackup: '清除备用',\n provider: '提供方',\n providerPlaceholder: 'provider,如 mt',\n loadCandidates: '加载候选',\n loading: '加载中…',\n candidates: '候选模型',\n setBackup: '设为备用',\n currentBackup: '当前备用',\n currentBackupMark: '备用',\n noCandidates: '未加载到候选模型',\n empty: '暂无渠道数据',\n};\nexport const en = {\n status: 'Channel status',\n current: 'Current',\n backup: 'Backup',\n backupNone: 'none',\n backupManage: 'Backup channel',\n backupManageHint: 'Pick a backup channel from the candidate list',\n failoverCount: 'failovers',\n lastFailover: 'last failover',\n healthy: 'healthy',\n cooldown: 'cooling',\n probe: 'probing',\n refresh: 'Refresh',\n close: 'Close',\n clearBackup: 'Clear backup',\n provider: 'Provider',\n providerPlaceholder: 'provider, e.g. mt',\n loadCandidates: 'Load candidates',\n loading: 'Loading…',\n candidates: 'Candidate models',\n setBackup: 'Set as backup',\n currentBackup: 'Current backup',\n currentBackupMark: 'backup',\n noCandidates: 'No candidates loaded',\n empty: 'No channel data yet',\n};\n//# sourceMappingURL=locales.js.map","/**\n * Client-side wire types and RPC wrapper for the `/dsh-daruma` channel.\n * Structural types only — no monorepo-internal imports.\n */\nexport function createApi(rpc) {\n const call = async (endpoint, payload) => {\n const result = (await rpc(endpoint, payload));\n if (!result.ok) {\n throw new Error(result.error?.message ?? `daruma rpc ${endpoint} failed`);\n }\n return result.value;\n };\n return {\n status: () => call('status'),\n listCandidates: (provider) => call('listCandidates', { provider }),\n setBackup: async (provider, model) => {\n await call('setBackup', { provider, model });\n },\n clearBackup: async () => {\n await call('clearBackup');\n },\n };\n}\n//# sourceMappingURL=api.js.map","/**\n * Time-aware channel-health classification for the status dock.\n *\n * The host exposes no request-success event, so a channel whose cooldown has\n * expired keeps its `COOLDOWN` state field forever — it becomes routable again\n * (`canRouteNow`) without ever flipping back to `HEALTHY`. The dock therefore\n * must judge by time, not by the raw state field: only a channel that is\n * *still* cooling (cooldown not yet expired) counts as an error.\n */\n/**\n * Overall dock state:\n * - `error` — at least one channel is still cooling (`cooldownUntilMs > now`).\n * - `warning` — a probe is in flight (kept for parity; the adapter no longer\n * enters PROBE, but persisted legacy states may surface it).\n * - `done` — everything routable: healthy, or cooled down long enough.\n * - `ongoing` — no snapshot yet.\n */\nexport function overallState(channels, nowMs) {\n if (channels === null)\n return 'ongoing';\n if (channels.some((c) => c.state === 'COOLDOWN' && c.cooldownUntilMs > nowMs))\n return 'error';\n if (channels.some((c) => c.state === 'PROBE'))\n return 'warning';\n return 'done';\n}\n//# sourceMappingURL=health.js.map","import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\n/**\n * BackupChannelPanel: list candidate models for a provider and pick one as\n * the failover backup. Rendered inside a primitives Modal.\n *\n * No probing happens here anymore — the panel is a plain picker. Channel\n * health still updates from real traffic via the recovery engine.\n */\nimport { memo, useCallback, useEffect, useMemo, useState } from 'react';\nimport { Button, Modal, Pill, } from '@deepseek-ai/dsh-client-ui-primitives';\nfunction deriveProvider(status) {\n if (status === null)\n return '';\n if (status.current !== null)\n return status.current.split('::')[0] ?? '';\n if (status.backup !== null)\n return status.backup.provider;\n return status.providers[0] ?? '';\n}\nconst sectionStyle = {\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n padding: '12px 0',\n fontSize: '13px',\n};\nconst rowStyle = {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n};\nconst noteStyle = { color: 'var(--dsw-text-tertiary, #999)', fontSize: '12px' };\n/** Clamp a long provider/model name so the row never wraps. */\nconst backupPillStyle = {\n flex: '1 1 auto',\n minWidth: 0,\n overflow: 'hidden',\n};\nconst ellipsisStyle = {\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n};\nconst listStyle = {\n maxHeight: 300,\n overflowY: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n contain: 'content',\n willChange: 'scroll-position',\n overscrollBehavior: 'contain',\n};\n/** Skip rendering rows outside the viewport while scrolling. */\nconst candidateRowStyle = {\n ...rowStyle,\n contentVisibility: 'auto',\n containIntrinsicSize: '28px',\n};\n/** One candidate row, memoized so selection changes only re-render it. */\nconst CandidateRow = memo(function CandidateRow(props) {\n const { candidate, isBackup, busy, t, onSetBackup } = props;\n return (_jsxs(\"div\", { style: candidateRowStyle, children: [_jsx(\"span\", { style: { width: 14, flexShrink: 0 } }), _jsx(\"span\", { style: { flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: candidate.model }), isBackup && _jsx(Pill, { active: true, children: t('currentBackupMark') }), _jsx(Button, { size: \"sm\", variant: \"ghost\", disabled: isBackup || busy, onClick: () => onSetBackup(candidate.model), children: t('setBackup') })] }));\n});\nexport function BackupPanel(props) {\n const { api, t, status, onClose } = props;\n const [provider, setProvider] = useState(deriveProvider(status));\n const [candidates, setCandidates] = useState(null);\n const [loading, setLoading] = useState(false);\n const [busy, setBusy] = useState(null);\n const [error, setError] = useState(null);\n // Local overlay on the status-prop backup: applied optimistically after\n // set/clear so the row reflects the change without waiting for the parent\n // to re-fetch status. Cleared whenever a fresh status arrives.\n const [backupOverride, setBackupOverride] = useState(undefined);\n // The effective backup shown in the panel: local override → status prop.\n const backupShown = backupOverride !== undefined ? backupOverride : status?.backup ?? null;\n // O(1) lookup for the current backup model; re-built only when the effective backup changes.\n const backupModel = useMemo(() => (backupShown !== null && backupShown.provider === provider ? backupShown.model : null), [backupShown, provider]);\n const loadCandidates = async () => {\n if (provider === '')\n return;\n setLoading(true);\n setError(null);\n try {\n setCandidates(await api.listCandidates(provider));\n }\n catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause));\n }\n finally {\n setLoading(false);\n }\n };\n useEffect(() => {\n if (provider !== '')\n void loadCandidates();\n }, [provider]);\n // A fresh status from the parent supersedes the local override.\n useEffect(() => {\n setBackupOverride(undefined);\n }, [status]);\n const setBackup = async (model) => {\n setBusy(model);\n setError(null);\n try {\n await api.setBackup(provider, model);\n setBackupOverride({ provider, model });\n }\n catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause));\n }\n finally {\n setBusy(null);\n }\n };\n const clearBackup = async () => {\n setBusy('__clear__');\n setError(null);\n try {\n await api.clearBackup();\n setBackupOverride(null);\n }\n catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause));\n }\n finally {\n setBusy(null);\n }\n };\n // Stable callback so memoized CandidateRow props don't change every render.\n const handleSetBackup = useCallback((model) => void setBackup(model), [provider]);\n return (_jsx(Modal, { open: true, onClose: onClose, title: t('backupManage'), className: \"daruma-wide-dialog\", closeLabel: t('close'), description: t('backupManageHint'), footer: _jsx(Button, { variant: \"primary\", onClick: onClose, children: t('close') }), children: _jsxs(\"div\", { style: sectionStyle, children: [status !== null && status.failoverCount > 0 && (_jsxs(\"div\", { style: noteStyle, children: [t('failoverCount'), \": \", status.failoverCount, status.failoverHistory.length > 0 && (_jsxs(_Fragment, { children: [' · ', t('lastFailover'), \": \", status.failoverHistory.map((h) => `${h.from} → ${h.to}`).join(' · ')] }))] })), backupShown !== null && (_jsxs(\"div\", { style: rowStyle, children: [_jsxs(\"span\", { style: { flexShrink: 0 }, children: [t('currentBackup'), \":\"] }), _jsx(Pill, { active: true, style: backupPillStyle, title: `${backupShown.provider}/${backupShown.model}`, children: _jsxs(\"span\", { style: ellipsisStyle, children: [backupShown.provider, \"/\", backupShown.model] }) }), _jsx(Button, { size: \"sm\", variant: \"ghost\", style: { flexShrink: 0 }, disabled: busy !== null, onClick: () => void clearBackup(), children: t('clearBackup') })] })), _jsxs(\"div\", { style: rowStyle, children: [(status?.providers ?? []).length > 0 ? (_jsx(\"select\", { value: provider, disabled: loading, onChange: (event) => setProvider(event.currentTarget.value), style: { flex: 1, padding: '4px 8px', fontSize: 13 }, children: status?.providers.map((name) => (_jsx(\"option\", { value: name, children: name }, name))) })) : (_jsx(\"input\", { value: provider, placeholder: t('providerPlaceholder'), onChange: (event) => setProvider(event.currentTarget.value), style: { flex: 1, padding: '4px 8px', fontSize: 13 } })), _jsx(Button, { size: \"sm\", variant: \"outline\", onClick: () => void loadCandidates(), disabled: provider === '' || loading, children: loading ? t('loading') : t('loadCandidates') })] }), error !== null && _jsx(\"div\", { style: { color: 'var(--dsw-text-danger, #e5484d)' }, children: error }), candidates !== null && (_jsxs(_Fragment, { children: [_jsx(\"div\", { style: rowStyle, children: _jsxs(\"span\", { children: [t('candidates'), \" (\", candidates.length, \")\"] }) }), candidates.length === 0 && _jsx(\"div\", { style: noteStyle, children: t('noCandidates') }), _jsx(\"div\", { style: listStyle, children: candidates.map((candidate) => (_jsx(CandidateRow, { candidate: candidate, isBackup: candidate.model === backupModel, busy: busy !== null, t: t, onSetBackup: handleSetBackup }, candidate.model))) })] }))] }) }));\n}\n//# sourceMappingURL=BackupPanel.js.map","import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from \"react/jsx-runtime\";\n/**\n * DarumaStatus: a compact control at the right end of the composer tool row,\n * next to the model selector. Shows overall channel health and the backup\n * selection; clicking it opens the backup-channel panel.\n */\nimport { useCallback, useEffect, useState } from 'react';\nimport { Button, IconCheckOutline16, IconWarningOutline16 } from '@deepseek-ai/dsh-client-ui-primitives';\nimport { overallState } from \"./health.js\";\nimport { BackupPanel } from \"./BackupPanel.js\";\nconst controlStyle = {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 6,\n maxWidth: 220,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n};\nconst iconColor = {\n done: 'var(--dsw-text-success, #30a46c)',\n warning: 'var(--dsw-text-warning, #f5a524)',\n error: 'var(--dsw-text-danger, #e5484d)',\n ongoing: 'var(--dsw-text-secondary, #888)',\n};\n/** Status glyph: a check when healthy, a warning otherwise. */\nfunction StatusIcon(props) {\n return (_jsx(\"span\", { style: { display: 'inline-flex', color: iconColor[props.state], flexShrink: 0 }, children: props.state === 'done'\n ? _jsx(IconCheckOutline16, { size: 14 })\n : _jsx(IconWarningOutline16, { size: 14 }) }));\n}\nexport function StatusDock(props) {\n const [status, setStatus] = useState(null);\n const [panelOpen, setPanelOpen] = useState(false);\n const load = useCallback(async () => {\n try {\n const value = await props.api.status();\n setStatus(value);\n }\n catch {\n // keep last good snapshot; the control stays quiet on RPC failure\n }\n }, [props.api]);\n useEffect(() => {\n void load();\n const timer = setInterval(() => void load(), 30_000);\n return () => clearInterval(timer);\n }, [load]);\n const t = props.t;\n const backupLabel = status?.backup !== null && status?.backup !== undefined\n ? `${status.backup.provider}/${status.backup.model}`\n : t('backupNone');\n return (_jsxs(_Fragment, { children: [_jsxs(Button, { size: \"sm\", variant: \"ghost\", title: t('backupManageHint'), onClick: () => setPanelOpen(true), style: controlStyle, children: [_jsx(StatusIcon, { state: overallState(status?.channels ?? null, Date.now()) }), _jsxs(\"span\", { style: { minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: [t('backup'), \": \", backupLabel] })] }), panelOpen && (_jsx(BackupPanel, { api: props.api, t: t, status: status, onClose: () => {\n setPanelOpen(false);\n void load();\n } }))] }));\n}\n//# sourceMappingURL=StatusDock.js.map","/**\n * dsh-daruma client: registers a compact channel-status dock above the\n * composer (conversation.input.dock) with a \"backup channel\" panel that\n * lists candidate models and picks a backup. Built by tsdown into the\n * __ModuleLoader__ factory bundle at lib/client.js.\n */\nimport { createElement as h } from 'react';\nimport { en, zh } from \"./locales.js\";\nimport { createApi } from \"./api.js\";\nimport { StatusDock } from \"./StatusDock.js\";\nconst NS = 'daruma';\nexport const name = 'dsh-daruma';\nexport const inject = ['slots', 'locale'];\nexport function apply(ctx) {\n // Widen the backup-panel dialog: the primitives Modal card is fixed at\n // min(380px, 100%), which truncates long provider/model names. A global\n // class (not a CSS module) outranks the module-scoped `.dialog` rule.\n if (typeof document !== 'undefined') {\n const tagId = 'daruma-panel-style';\n if (document.querySelector(`style[data-daruma=\"${tagId}\"]`) === null) {\n const style = document.createElement('style');\n style.dataset.daruma = tagId;\n style.textContent = '.daruma-wide-dialog.daruma-wide-dialog { width: min(560px, 100%); }';\n document.head.appendChild(style);\n }\n }\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-daruma: dictionaries');\n const t = ctx.locale.bind(NS);\n const connection = ctx.get('connection');\n if (connection === undefined) {\n console.warn('[dsh-daruma] web transport unavailable — client UI disabled');\n return;\n }\n const rpc = (endpoint, payload) => connection.rpc.call('/dsh-daruma', endpoint, payload ?? {});\n const api = createApi(rpc);\n ctx.slots.inject('conversation.input.right', () => ctx.slots.register({\n name: 'conversation.input.right',\n id: 'daruma-status',\n order: 0,\n inject: () => ({ api, t }),\n }, () => h(StatusDock, { api, t })));\n}\n//# sourceMappingURL=index.js.map"],"mappings":"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"}
package/lib/config.js CHANGED
@@ -9,16 +9,46 @@ export function defaultStateFile() {
9
9
  return join(homedir(), '.dsh', 'daruma', 'channel-health.json');
10
10
  }
11
11
  export function resolveConfig(raw = {}) {
12
- const channels = (raw.channels ?? []).map((entry) => ({
13
- id: channelIdOf(entry.provider, entry.model),
14
- provider: entry.provider,
15
- model: modelId(entry.model),
16
- }));
12
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
13
+ throw new Error('invalid config: expected an object');
14
+ if (raw.channels !== undefined && !Array.isArray(raw.channels)) {
15
+ throw new Error('invalid channels: expected an array');
16
+ }
17
+ const channels = (raw.channels ?? []).map((entry, index) => {
18
+ if (!entry || typeof entry.provider !== 'string' || typeof entry.model !== 'string'
19
+ || entry.provider.trim() === '' || entry.model.trim() === '') {
20
+ throw new Error(`invalid channel at index ${index}: provider/model must be non-empty strings`);
21
+ }
22
+ if (entry.provider.length > 256 || entry.model.length > 256) {
23
+ throw new Error(`invalid channel at index ${index}: provider/model too long`);
24
+ }
25
+ return {
26
+ id: channelIdOf(entry.provider, entry.model),
27
+ provider: entry.provider,
28
+ model: modelId(entry.model),
29
+ };
30
+ });
31
+ const ids = new Set(channels.map((channel) => channel.id));
32
+ if (ids.size !== channels.length)
33
+ throw new Error('invalid channels: duplicate provider/model pair');
34
+ const positiveInteger = (value, fallback, name) => {
35
+ const resolved = value ?? fallback;
36
+ if (!Number.isSafeInteger(resolved) || resolved <= 0) {
37
+ throw new Error(`invalid ${name}: expected a positive integer`);
38
+ }
39
+ return resolved;
40
+ };
41
+ const failureBudget = positiveInteger(raw.failureBudget, 3, 'failureBudget');
42
+ const cooldownMs = positiveInteger(raw.cooldownMs, 30_000, 'cooldownMs');
43
+ const giveUpBudget = positiveInteger(raw.giveUpBudget, 8, 'giveUpBudget');
44
+ if (raw.stateFile !== undefined && (typeof raw.stateFile !== 'string' || raw.stateFile.trim() === '')) {
45
+ throw new Error('invalid stateFile: expected a non-empty string');
46
+ }
17
47
  return {
18
48
  channels,
19
- failureBudget: raw.failureBudget ?? 3,
20
- cooldownMs: raw.cooldownMs ?? 30_000,
21
- giveUpBudget: raw.giveUpBudget ?? 8,
49
+ failureBudget,
50
+ cooldownMs,
51
+ giveUpBudget,
22
52
  stateFile: raw.stateFile || defaultStateFile(),
23
53
  };
24
54
  }
package/lib/config.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAA2C,MAAM,aAAa,CAAA;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAmB1C,MAAM,UAAU,gBAAgB;IAC9B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAA;AACjE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAoB,EAAE;IAClD,MAAM,QAAQ,GAAc,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC/D,EAAE,EAAE,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC;QAC5C,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;KAC5B,CAAC,CAAC,CAAA;IAEH,OAAO;QACL,QAAQ;QACR,aAAa,EAAE,GAAG,CAAC,aAAa,IAAI,CAAC;QACrC,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,MAAM;QACpC,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,CAAC;QACnC,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,gBAAgB,EAAE;KAC/C,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAA2C,MAAM,aAAa,CAAA;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAmB1C,MAAM,UAAU,gBAAgB;IAC9B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAA;AACjE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAoB,EAAE;IAClD,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;IACxH,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,CAAC;IACD,MAAM,QAAQ,GAAc,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QACpE,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;eAC9E,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC/D,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,4CAA4C,CAAC,CAAA;QAChG,CAAC;QACD,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YAC5D,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,2BAA2B,CAAC,CAAA;QAC/E,CAAC;QACD,OAAO;YACL,EAAE,EAAE,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC;YAC5C,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;SAC5B,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1D,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;IAEpG,MAAM,eAAe,GAAG,CAAC,KAAyB,EAAE,QAAgB,EAAE,IAAY,EAAU,EAAE;QAC5F,MAAM,QAAQ,GAAG,KAAK,IAAI,QAAQ,CAAA;QAClC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,+BAA+B,CAAC,CAAA;QACjE,CAAC;QACD,OAAO,QAAQ,CAAA;IACjB,CAAC,CAAA;IACD,MAAM,aAAa,GAAG,eAAe,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,EAAE,eAAe,CAAC,CAAA;IAC5E,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,CAAA;IACxE,MAAM,YAAY,GAAG,eAAe,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,EAAE,cAAc,CAAC,CAAA;IACzE,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,IAAI,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACtG,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAA;IACnE,CAAC;IAED,OAAO;QACL,QAAQ;QACR,aAAa;QACb,UAAU;QACV,YAAY;QACZ,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,gBAAgB,EAAE;KAC/C,CAAA;AACH,CAAC"}
package/lib/engine.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * RecoveryEngine — the adapter-side state holder that wraps the pure
3
3
  * `decide()` from daruma-core.
4
4
  *
5
- * It owns the mutable channel-health map, the per-session failover counter,
5
+ * It owns the mutable channel-health map and per-scope failover counters,
6
6
  * and persistence through a `ChannelHealthStore`. All decision logic stays in
7
7
  * daruma-core; this class only threads state and I/O.
8
8
  */
@@ -11,6 +11,8 @@ export interface ChannelHealthView {
11
11
  readonly channel: ChannelId;
12
12
  readonly state: ChannelState;
13
13
  readonly failures: number;
14
+ /** Epoch ms when the channel's cooldown ends; `0` when not cooling. */
15
+ readonly cooldownUntilMs: number;
14
16
  }
15
17
  export interface FailoverRecord {
16
18
  readonly from: string;
@@ -23,13 +25,17 @@ export declare class RecoveryEngine {
23
25
  private readonly store;
24
26
  private readonly healths;
25
27
  private failoverTotal;
28
+ private readonly failoversByScope;
26
29
  private readonly failoverHistory;
27
30
  private readonly clock;
28
31
  constructor(config: RecoveryPolicyConfig, store: ChannelHealthStore, clock?: Clock);
29
32
  /** Load every configured channel's persisted health into memory. */
30
33
  private preload;
31
- /** Feed one failure signal and persist the resulting state. */
32
- onFailure(signal: FailureSignal, preferred?: Channel): RecoveryPlan;
34
+ /** Feed one failure signal and persist the resulting state. `scope` should
35
+ * identify an agent/session so independent tasks do not share a budget. */
36
+ onFailure(signal: FailureSignal, preferred?: Channel, scope?: string): RecoveryPlan;
37
+ /** Release per-agent/session counters when the host disposes the scope. */
38
+ clearScope(scope: string): void;
33
39
  /** Snapshot of every tracked channel's health, for the status UI. */
34
40
  listHealth(): ChannelHealthView[];
35
41
  get failoverCount(): number;
package/lib/engine.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * RecoveryEngine — the adapter-side state holder that wraps the pure
3
3
  * `decide()` from daruma-core.
4
4
  *
5
- * It owns the mutable channel-health map, the per-session failover counter,
5
+ * It owns the mutable channel-health map and per-scope failover counters,
6
6
  * and persistence through a `ChannelHealthStore`. All decision logic stays in
7
7
  * daruma-core; this class only threads state and I/O.
8
8
  */
@@ -14,6 +14,7 @@ export class RecoveryEngine {
14
14
  store;
15
15
  healths = new Map();
16
16
  failoverTotal = 0;
17
+ failoversByScope = new Map();
17
18
  failoverHistory = [];
18
19
  clock;
19
20
  constructor(config, store, clock) {
@@ -31,12 +32,14 @@ export class RecoveryEngine {
31
32
  this.healths.set(channel.id, stored ?? freshHealth(channel.id, this.clock.nowMs()));
32
33
  }
33
34
  }
34
- /** Feed one failure signal and persist the resulting state. */
35
- onFailure(signal, preferred) {
35
+ /** Feed one failure signal and persist the resulting state. `scope` should
36
+ * identify an agent/session so independent tasks do not share a budget. */
37
+ onFailure(signal, preferred, scope = 'global') {
38
+ const scopedCount = this.failoversByScope.get(scope) ?? 0;
36
39
  const plan = decide({
37
40
  signal,
38
41
  healths: this.healths,
39
- failoverCount: this.failoverTotal,
42
+ failoverCount: scopedCount,
40
43
  config: this.config,
41
44
  nowMs: this.clock.nowMs(),
42
45
  ...(preferred !== undefined ? { preferred } : {}),
@@ -44,7 +47,8 @@ export class RecoveryEngine {
44
47
  this.healths.set(signal.channel, plan.healthAfter);
45
48
  this.store.save(plan.healthAfter);
46
49
  if (plan.verdict.kind === 'FAILOVER') {
47
- this.failoverTotal = plan.failoverCount;
50
+ this.failoversByScope.set(scope, plan.failoverCount);
51
+ this.failoverTotal += 1;
48
52
  this.failoverHistory.push({
49
53
  from: signal.channel,
50
54
  to: plan.verdict.target.id,
@@ -57,12 +61,17 @@ export class RecoveryEngine {
57
61
  }
58
62
  return plan;
59
63
  }
64
+ /** Release per-agent/session counters when the host disposes the scope. */
65
+ clearScope(scope) {
66
+ this.failoversByScope.delete(scope);
67
+ }
60
68
  /** Snapshot of every tracked channel's health, for the status UI. */
61
69
  listHealth() {
62
70
  return [...this.healths.values()].map((health) => ({
63
71
  channel: health.channel,
64
72
  state: health.state,
65
73
  failures: health.consecutiveFailures,
74
+ cooldownUntilMs: health.cooldownUntilMs,
66
75
  }));
67
76
  }
68
77
  get failoverCount() {
package/lib/engine.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
package/lib/index.js CHANGED
@@ -57,7 +57,7 @@ export function apply(ctx, rawConfig = {}) {
57
57
  ctx.on('agent/request-error', async (payload, next) => {
58
58
  const channel = currentChannel.get(payload.agent.id) ?? channelIdOf(payload.provider, '');
59
59
  const signal = toFailureSignal(payload.failure, channel, Date.now());
60
- const plan = engine.onFailure(signal, backupChannel());
60
+ const plan = engine.onFailure(signal, backupChannel(), payload.agent.id);
61
61
  if (plan.verdict.kind === 'FAILOVER') {
62
62
  pending.set(payload.agent.id, plan.verdict.target);
63
63
  const eventData = { from: channel, to: plan.verdict.target.id, reason: signal.code, at: Date.now() };
@@ -71,6 +71,11 @@ export function apply(ctx, rawConfig = {}) {
71
71
  // RETRY_NOW / GIVE_UP: delegate downstream (retry may still own it).
72
72
  return next();
73
73
  });
74
+ ctx.on('agent/disposed', ({ agent }) => {
75
+ currentChannel.delete(agent.id);
76
+ pending.delete(agent.id);
77
+ engine.clearScope(agent.id);
78
+ });
74
79
  mountRpc(ctx, { engine, currentChannel, status, getLlm: () => ctx.llm, getSettings: () => ctx.settings });
75
80
  }
76
81
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC5F,OAAO,EAAE,aAAa,EAAqB,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAA;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACnC,OAAO,EAAE,OAAO,EAAgC,MAAM,aAAa,CAAA;AAEnE,MAAM,CAAC,MAAM,IAAI,GAAG,YAAY,CAAA;AAChC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAU,CAAA;AAgB5D,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,YAA0B,EAAE;IAC9D,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC,CAAA;IACvC,MAAM,KAAK,GAAG,IAAI,0BAA0B,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IAC9D,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAChD,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAA;IAE/B,sEAAsE;IACtE,MAAM,cAAc,GAAG,IAAI,GAAG,EAAqB,CAAA;IACnD,kEAAkE;IAClE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmB,CAAA;IAE1C,0DAA0D;IAC1D,MAAM,aAAa,GAAG,GAAwB,EAAE;QAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAA;QACjC,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,SAAS,CAAA;QAC1C,OAAO,EAAE,EAAE,EAAE,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAA;IACpH,CAAC,CAAA;IAED,GAAG,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC9C,MAAM,OAAO,GAAkB,MAAM,IAAI,EAAE,CAAA;QAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC3C,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YAChC,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;YAC5C,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAA;YAChE,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,yBAAyB,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,KAAK,OAAO,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,KAAK,EAAE,CACrG,CAAA;YACD,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAA;QAChE,OAAO,OAAO,CAAA;IAChB,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,EAAE,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAA+B,EAAE;QACjF,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,WAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QACzF,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;QACpE,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAExE,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YAClD,MAAM,SAAS,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAA;YACpG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAA;YAC1D,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,wBAAwB,OAAO,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,MAAM,CAAC,IAAI,GAAG,CAChF,CAAA;YACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;QAC1B,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACpC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA;QACpE,CAAC;QAED,qEAAqE;QACrE,OAAO,IAAI,EAAE,CAAA;IACf,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;QACrC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACxB,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAA;AAC3G,CAAC"}
package/lib/rpc.js CHANGED
@@ -2,7 +2,6 @@
2
2
  * `/dsh-daruma` RPC channel: status snapshot, candidate discovery, and
3
3
  * backup-channel management for the client UI.
4
4
  */
5
- import { channelIdOf } from "./mapping.js";
6
5
  function messageOf(error) {
7
6
  return error instanceof Error ? error.message : String(error);
8
7
  }
@@ -12,10 +11,13 @@ function isRecord(value) {
12
11
  function isString(value) {
13
12
  return typeof value === 'string';
14
13
  }
14
+ function isIdentifier(value) {
15
+ return isString(value) && value.trim() !== '' && value.length <= 256;
16
+ }
15
17
  /** `{ provider, model }` — a backup selection. */
16
18
  function isBackupPayload(value) {
17
- return isRecord(value) && isString(value.provider) && value.provider !== ''
18
- && isString(value.model) && value.model !== '';
19
+ return isRecord(value) && isIdentifier(value.provider)
20
+ && isIdentifier(value.model);
19
21
  }
20
22
  /** Known provider names: daruma's configured channels plus settings providers. */
21
23
  function knownProviders(deps) {
@@ -65,7 +67,7 @@ export function mountRpc(ctx, deps) {
65
67
  const connection = ctx.get('connection');
66
68
  if (connection === undefined)
67
69
  return; // no web transport (headless)
68
- const dispatch = async (endpoint, payload, signal) => {
70
+ const dispatch = async (endpoint, payload, _signal) => {
69
71
  try {
70
72
  switch (endpoint) {
71
73
  case 'status': {
@@ -85,7 +87,7 @@ export function mountRpc(ctx, deps) {
85
87
  };
86
88
  }
87
89
  case 'listCandidates': {
88
- const provider = isRecord(payload) && isString(payload.provider) ? payload.provider : undefined;
90
+ const provider = isRecord(payload) && isIdentifier(payload.provider) ? payload.provider : undefined;
89
91
  if (provider === undefined)
90
92
  throw new Error('bad-request: listCandidates needs a provider');
91
93
  const llm = deps.getLlm();
package/lib/rpc.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rpc.js","sourceRoot":"","sources":["../src/rpc.ts"],"names":[],"mappings":"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"}
package/lib/store.js CHANGED
@@ -4,8 +4,18 @@
4
4
  * Persistence is best-effort: a corrupt or unreadable state file makes the
5
5
  * store start fresh rather than crashing the plugin.
6
6
  */
7
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
7
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
8
8
  import { dirname } from 'node:path';
9
+ function isHealth(value, key) {
10
+ if (typeof value !== 'object' || value === null)
11
+ return false;
12
+ const h = value;
13
+ return h.channel === key
14
+ && (h.state === 'HEALTHY' || h.state === 'COOLDOWN' || h.state === 'PROBE')
15
+ && Number.isSafeInteger(h.consecutiveFailures) && h.consecutiveFailures >= 0
16
+ && Number.isFinite(h.cooldownUntilMs) && h.cooldownUntilMs >= 0
17
+ && Number.isFinite(h.updatedAtMs) && h.updatedAtMs >= 0;
18
+ }
9
19
  export class JsonFileChannelHealthStore {
10
20
  file;
11
21
  healths = new Map();
@@ -20,9 +30,12 @@ export class JsonFileChannelHealthStore {
20
30
  try {
21
31
  if (!existsSync(this.file))
22
32
  return;
33
+ if (!statSync(this.file).isFile())
34
+ return;
23
35
  const raw = JSON.parse(readFileSync(this.file, 'utf8'));
24
36
  for (const [key, health] of Object.entries(raw.healths ?? {})) {
25
- this.healths.set(key, health);
37
+ if (isHealth(health, key))
38
+ this.healths.set(key, health);
26
39
  }
27
40
  }
28
41
  catch {
@@ -44,7 +57,22 @@ export class JsonFileChannelHealthStore {
44
57
  const healths = {};
45
58
  for (const [key, health] of this.healths)
46
59
  healths[key] = health;
47
- writeFileSync(this.file, JSON.stringify({ healths }, null, 2));
60
+ const temporary = `${this.file}.tmp-${process.pid}`;
61
+ const serialized = JSON.stringify({ healths }, null, 2);
62
+ writeFileSync(temporary, serialized, { mode: 0o600 });
63
+ try {
64
+ renameSync(temporary, this.file);
65
+ }
66
+ catch {
67
+ // Keep a compatibility fallback for filesystems where replacement
68
+ // rename is unavailable.
69
+ writeFileSync(this.file, serialized, { mode: 0o600 });
70
+ try {
71
+ unlinkSync(temporary);
72
+ }
73
+ catch { /* best effort cleanup */ }
74
+ }
75
+ chmodSync(this.file, 0o600);
48
76
  }
49
77
  catch {
50
78
  // Persistence failure must not take down the plugin.
package/lib/store.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAOnC,MAAM,OAAO,0BAA0B;IAIR;IAHZ,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAA;IACtD,MAAM,GAAG,KAAK,CAAA;IAEtB,YAA6B,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IAAG,CAAC;IAErC,YAAY;QAClB,IAAI,IAAI,CAAC,MAAM;YAAE,OAAM;QACvB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;QAClB,IAAI,CAAC;YACH,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAM;YAClC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAgB,CAAA;YACtE,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC9D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAgB,EAAE,MAAuB,CAAC,CAAA;YAC7D,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,8BAA8B;QAChC,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAkB;QACrB,IAAI,CAAC,YAAY,EAAE,CAAA;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAClC,CAAC;IAED,IAAI,CAAC,MAAqB;QACxB,IAAI,CAAC,YAAY,EAAE,CAAA;QACnB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QACxC,IAAI,CAAC,OAAO,EAAE,CAAA;IAChB,CAAC;IAEO,OAAO;QACb,IAAI,CAAC;YACH,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAClD,MAAM,OAAO,GAAkC,EAAE,CAAA;YACjD,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAA;YAC/D,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-daruma",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Daruma resilience plugin for DeepSeek Harness — detects model-request failures and fails over to another channel to keep long tasks alive.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -38,6 +38,11 @@
38
38
  "engines": {
39
39
  "node": ">=22.0.0"
40
40
  },
41
+ "scripts": {
42
+ "build": "tsc -p tsconfig.build.json && tsdown",
43
+ "typecheck": "tsc --noEmit",
44
+ "test": "vitest run --passWithNoTests"
45
+ },
41
46
  "keywords": [
42
47
  "deepseek-harness",
43
48
  "dsh",
@@ -83,10 +88,5 @@
83
88
  "tsdown": "^0.22.0",
84
89
  "typescript": "^5.7.0",
85
90
  "vitest": "^3.0.0"
86
- },
87
- "scripts": {
88
- "build": "tsc -p tsconfig.build.json && tsdown",
89
- "typecheck": "tsc --noEmit",
90
- "test": "vitest run --passWithNoTests"
91
91
  }
92
- }
92
+ }