@wowyuarm/dsh-agent-team 0.1.15 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +7 -3
  2. package/README.zh.md +7 -3
  3. package/package.json +49 -47
  4. package/packages/agent-team/lib/context-source.js +11 -6
  5. package/packages/agent-team/lib/environment-check.js +102 -0
  6. package/packages/agent-team/lib/human-profile.js +23 -37
  7. package/packages/agent-team/lib/index.js +28 -2
  8. package/packages/agent-team/lib/installed-manifest.js +32 -0
  9. package/packages/agent-team/lib/ledger.js +35 -0
  10. package/packages/agent-team/lib/member-context.js +2 -4
  11. package/packages/agent-team/lib/member-time-context.js +2 -4
  12. package/packages/agent-team/lib/pressure-policy.js +13 -8
  13. package/packages/agent-team/lib/typert.host.js +121 -44
  14. package/packages/agent-team/lib/typert.remote-client.d.ts +3 -1
  15. package/packages/agent-team/lib/typert.remote-client.d.ts.map +1 -1
  16. package/packages/agent-team/lib/typert.remote-client.js +86 -38
  17. package/packages/agent-team/lib/types/context-source.d.ts +7 -4
  18. package/packages/agent-team/lib/types/context-source.d.ts.map +1 -1
  19. package/packages/agent-team/lib/types/environment-check.d.ts +66 -0
  20. package/packages/agent-team/lib/types/environment-check.d.ts.map +1 -0
  21. package/packages/agent-team/lib/types/human-profile.d.ts +21 -27
  22. package/packages/agent-team/lib/types/human-profile.d.ts.map +1 -1
  23. package/packages/agent-team/lib/types/index.d.ts +23 -2
  24. package/packages/agent-team/lib/types/index.d.ts.map +1 -1
  25. package/packages/agent-team/lib/types/installed-manifest.d.ts +16 -0
  26. package/packages/agent-team/lib/types/installed-manifest.d.ts.map +1 -0
  27. package/packages/agent-team/lib/types/ledger.d.ts +12 -0
  28. package/packages/agent-team/lib/types/ledger.d.ts.map +1 -1
  29. package/packages/agent-team/lib/types/member-context.d.ts.map +1 -1
  30. package/packages/agent-team/lib/types/member-time-context.d.ts.map +1 -1
  31. package/packages/agent-team/lib/types/pressure-policy.d.ts +5 -1
  32. package/packages/agent-team/lib/types/pressure-policy.d.ts.map +1 -1
  33. package/packages/agent-team/lib/types/types/entities.d.ts +1 -8
  34. package/packages/agent-team/lib/types/types/entities.d.ts.map +1 -1
  35. package/packages/agent-team/lib/types/types/requests-results.d.ts +66 -0
  36. package/packages/agent-team/lib/types/types/requests-results.d.ts.map +1 -1
  37. package/packages/client-agent-team/lib/client.js +324 -75
  38. package/packages/client-agent-team/lib/client.js.map +1 -1
  39. package/packages/client-agent-team/lib/types/client/EnvironmentCheck.d.ts +18 -0
  40. package/packages/client-agent-team/lib/types/client/EnvironmentCheck.d.ts.map +1 -0
  41. package/packages/client-agent-team/lib/types/client/EnvironmentCheck.js +58 -0
  42. package/packages/client-agent-team/lib/types/client/HumanSettingsSection.d.ts +3 -0
  43. package/packages/client-agent-team/lib/types/client/HumanSettingsSection.d.ts.map +1 -1
  44. package/packages/client-agent-team/lib/types/client/HumanSettingsSection.js +7 -4
  45. package/packages/client-agent-team/lib/types/client/TeamAgentsPanel.js +0 -5
  46. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts +1 -1
  47. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.d.ts.map +1 -1
  48. package/packages/client-agent-team/lib/types/client/TeamPresenceDot.js +2 -7
  49. package/packages/client-agent-team/lib/types/client/environment-check.d.ts +65 -0
  50. package/packages/client-agent-team/lib/types/client/environment-check.d.ts.map +1 -0
  51. package/packages/client-agent-team/lib/types/client/environment-check.js +78 -0
  52. package/packages/client-agent-team/lib/types/client/index.d.ts.map +1 -1
  53. package/packages/client-agent-team/lib/types/client/index.js +9 -0
  54. package/packages/client-agent-team/lib/types/client/locales.d.ts +18 -8
  55. package/packages/client-agent-team/lib/types/client/locales.d.ts.map +1 -1
  56. package/packages/client-agent-team/lib/types/client/locales.js +21 -8
  57. package/packages/tool-agent-team/lib/context-tools.js +106 -94
  58. package/packages/tool-agent-team/lib/index.js +17 -2
  59. package/packages/tool-agent-team/lib/types/context-tools.d.ts +16 -7
  60. package/packages/tool-agent-team/lib/types/context-tools.d.ts.map +1 -1
  61. package/packages/tool-agent-team/lib/types/index.d.ts.map +1 -1
@@ -0,0 +1,18 @@
1
+ import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import { type TeamEnvironmentSource } from './environment-check.ts';
3
+ /**
4
+ * The local environment check: which DSH line this installation runs against,
5
+ * and whether that line is inside the range the bundle declares.
6
+ *
7
+ * Three verdicts, never a fourth, and never a guess: a fact the Host could not
8
+ * establish is `undetermined`, not a mismatch. Every verdict is stated as text
9
+ * plus an icon, so the state survives a reader who cannot tell the colors
10
+ * apart. The support line is written in words rather than as a bare semver
11
+ * range, and the tested combination is printed only when the Host could derive
12
+ * both of its versions — the page never supplies a version of its own.
13
+ */
14
+ export type EnvironmentCheckProps = PropsLocale<'team'> & {
15
+ readonly environment: TeamEnvironmentSource;
16
+ };
17
+ export declare function EnvironmentCheck({ t, environment }: EnvironmentCheckProps): import("react").JSX.Element | null;
18
+ //# sourceMappingURL=EnvironmentCheck.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvironmentCheck.d.ts","sourceRoot":"","sources":["../../../src/client/EnvironmentCheck.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,EAAuB,KAAK,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAGxF;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,qBAAqB,GAC7B,WAAW,CAAC,MAAM,CAAC,GACnB;IAAE,QAAQ,CAAC,WAAW,EAAE,qBAAqB,CAAA;CAAE,CAAA;AAyBnD,wBAAgB,gBAAgB,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,qBAAqB,sCAkDzE"}
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEnvironmentCheck } from "./environment-check.js";
3
+ import css from './environment-check.module.css';
4
+ /** The three glyphs, drawn at the 16px seat the settings page uses for state marks. */
5
+ const ICONS = {
6
+ ok: _jsx("path", { d: "M3 8.5 6.5 12 13 4.5" }),
7
+ warn: _jsxs(_Fragment, { children: [_jsx("path", { d: "M8 2.5 14.6 13.6H1.4z" }), _jsx("path", { d: "M8 6.6v3.2" }), _jsx("path", { d: "M8 11.9h.01" })] }),
8
+ unknown: _jsxs(_Fragment, { children: [_jsx("circle", { cx: "8", cy: "8", r: "6" }), _jsx("path", { d: "M5.6 8h4.8" })] }),
9
+ };
10
+ function EnvironmentIcon({ glyph }) {
11
+ return _jsx("svg", { className: css.icon, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: ICONS[glyph] });
12
+ }
13
+ /** The release notes this bundle's own repository keeps, one click from the version footnote. */
14
+ const RELEASE_NOTES_URL = 'https://github.com/wowyuarm/dsh-agent-team/releases';
15
+ export function EnvironmentCheck({ t, environment }) {
16
+ const { report } = useEnvironmentCheck(environment);
17
+ // Nothing to state before the first read settles, and nothing to state if it
18
+ // never lands: the block is informational and its absence is not an error.
19
+ if (report === undefined)
20
+ return null;
21
+ const range = report.supportRange;
22
+ const running = report.dshVersion;
23
+ // The tested combination appears only when both of its versions were derived:
24
+ // the installed manifest's own version, and the range's lower bound, which is
25
+ // the certified line. A missing one withholds the line rather than inviting a
26
+ // hand-written version onto the page.
27
+ const certified = report.certifiedDshVersion;
28
+ const bundleVersion = report.bundleVersion;
29
+ // Both sides of the line have to be derived: `'unknown'` is the data layer's
30
+ // word for a version that could not be read, and it never reaches the page.
31
+ const tested = certified !== undefined && bundleVersion !== undefined && bundleVersion !== 'unknown';
32
+ const title = report.verdict === 'ok'
33
+ ? t('environmentOkTitle')
34
+ : report.verdict === 'out-of-range'
35
+ ? t('environmentOutOfRangeTitle')
36
+ : t('environmentUndeterminedTitle');
37
+ const lines = [];
38
+ if (report.verdict === 'ok') {
39
+ if (running !== undefined)
40
+ lines.push(t('environmentOkDetail', { version: running }));
41
+ }
42
+ else if (report.verdict === 'out-of-range') {
43
+ if (running !== undefined)
44
+ lines.push(t('environmentOutOfRangeDetail', { version: running }));
45
+ if (range !== undefined)
46
+ lines.push(t('environmentRange', { lower: range.lower, upper: range.upper }));
47
+ if (tested && certified !== undefined && bundleVersion !== undefined) {
48
+ lines.push(t('environmentTested', { bundle: bundleVersion, dsh: certified }));
49
+ }
50
+ }
51
+ else {
52
+ lines.push(t('environmentUndeterminedDetail'));
53
+ }
54
+ // `data-environment` carries the verdict the way the rest of the Client marks
55
+ // a state for assertions; the block also renders nothing at all before a read
56
+ // lands, so a journey can wait on this attribute rather than on prose.
57
+ return _jsxs("div", { className: css.block, "data-environment": report.verdict, children: [_jsx(EnvironmentIcon, { glyph: report.verdict === 'ok' ? 'ok' : report.verdict === 'out-of-range' ? 'warn' : 'unknown' }), _jsxs("div", { className: css.body, children: [_jsx("p", { className: css.title, children: title }), lines.map((line, index) => _jsx("p", { className: css.detail, children: line }, index)), report.verdict !== 'ok' && _jsx("p", { className: css.action, children: _jsx("a", { className: css.link, href: RELEASE_NOTES_URL, target: "_blank", rel: "noreferrer", children: t('environmentReleaseNotes') }) })] })] });
58
+ }
@@ -1,5 +1,6 @@
1
1
  import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
2
  import { type TeamHumanIdentityFace } from './human-identity.ts';
3
+ import type { TeamEnvironmentSource } from './environment-check.ts';
3
4
  export interface HumanSettingsSectionInjected {
4
5
  /** The shared Human identity projection: profile facts plus post-write refresh. */
5
6
  identity: TeamHumanIdentityFace;
@@ -9,6 +10,8 @@ export interface HumanSettingsSectionInjected {
9
10
  uploadAvatar: (file: File) => Promise<string | undefined>;
10
11
  /** Clear the avatar; the identity falls back to the initial. */
11
12
  removeAvatar: () => Promise<string | undefined>;
13
+ /** The local environment check, a read-only projection of the installation. */
14
+ environment: TeamEnvironmentSource;
12
15
  }
13
16
  export type HumanSettingsSectionProps = PropsRuntime<'settings.section'> & PropsLocale<'team'> & HumanSettingsSectionInjected;
14
17
  export declare function HumanSettingsSection(props: HumanSettingsSectionProps): import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"HumanSettingsSection.d.ts","sourceRoot":"","sources":["../../../src/client/HumanSettingsSection.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEjF,OAAO,EAAoB,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAiBlF,MAAM,WAAW,4BAA4B;IAC3C,mFAAmF;IACnF,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,sFAAsF;IACtF,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACvD,gGAAgG;IAChG,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACzD,gEAAgE;IAChE,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;CAChD;AAED,MAAM,MAAM,yBAAyB,GACjC,YAAY,CAAC,kBAAkB,CAAC,GAChC,WAAW,CAAC,MAAM,CAAC,GACnB,4BAA4B,CAAA;AAsBhC,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,+BAiKpE"}
1
+ {"version":3,"file":"HumanSettingsSection.d.ts","sourceRoot":"","sources":["../../../src/client/HumanSettingsSection.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEjF,OAAO,EAAoB,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAElF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAmBnE,MAAM,WAAW,4BAA4B;IAC3C,mFAAmF;IACnF,QAAQ,EAAE,qBAAqB,CAAA;IAC/B,sFAAsF;IACtF,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACvD,gGAAgG;IAChG,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACzD,gEAAgE;IAChE,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAC/C,+EAA+E;IAC/E,WAAW,EAAE,qBAAqB,CAAA;CACnC;AAED,MAAM,MAAM,yBAAyB,GACjC,YAAY,CAAC,kBAAkB,CAAC,GAChC,WAAW,CAAC,MAAM,CAAC,GACnB,4BAA4B,CAAA;AAsBhC,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,+BAkKpE"}
@@ -2,16 +2,19 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
2
2
  import { useRef, useState } from 'react';
3
3
  import { Button, Input } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { useHumanIdentity } from "./human-identity.js";
5
+ import { EnvironmentCheck } from "./EnvironmentCheck.js";
5
6
  import { useAvatarImage } from "./avatar-image.js";
6
7
  import css from './human-settings.module.css';
7
8
  /**
8
- * The Human's own settings page: display name, avatar, and the version
9
- * footnote.
9
+ * The Human's own settings page: display name, avatar, the local environment
10
+ * check, and the version footnote.
10
11
  *
11
12
  * The page owns no durable fact and no copy of one. Name, avatar, and version
12
13
  * all arrive from the shared identity projection, so a save here moves the
13
14
  * message rows and member refs at the same moment; a failed write keeps the
14
- * typed name in the field and reports the Host's own reason.
15
+ * typed name in the field and reports the Host's own reason. The environment
16
+ * check is a separate projection, read only, and belongs to the installation
17
+ * rather than to the Human.
15
18
  */
16
19
  /** Host-side avatar ceiling (`ATTACHMENT_MAX_BYTES`): the settings page refuses larger files before the round trip. */
17
20
  const AVATAR_MAX_BYTES = 10 * 1024 * 1024;
@@ -109,7 +112,7 @@ export function HumanSettingsSection(props) {
109
112
  : _jsx("img", { className: `${css.identity} ${css.identityImage}`, "data-avatar": "image", src: avatar.src, alt: "", onError: avatar.failed }), _jsx("input", { ref: filePicker, type: "file", accept: "image/*", tabIndex: -1, "aria-hidden": "true", hidden: true, onChange: (event) => {
110
113
  void pickAvatar(event.target.files?.[0]);
111
114
  event.target.value = '';
112
- } }), _jsx(Button, { variant: "outline", disabled: uploading, onClick: () => { filePicker.current?.click(); }, children: uploading ? t('humanSettingsUploading') : hasAvatar ? t('humanSettingsReplace') : t('humanSettingsUpload') }), hasAvatar && _jsx(Button, { disabled: uploading, onClick: () => { void removeAvatar(); }, children: t('humanSettingsRemoveAvatar') })] })] })] }), _jsxs("div", { className: css.footnote, children: [_jsx("span", { children: t('humanSettingsVersion', { version: profile.version ?? '' }) }), _jsx("span", { "aria-hidden": "true", children: "\u00B7" }), _jsx("a", { className: css.link, href: profile.repoUrl ?? '', target: "_blank", rel: "noreferrer", children: "GitHub" }), profile.updateAvailable && profile.latestVersion !== undefined
115
+ } }), _jsx(Button, { variant: "outline", disabled: uploading, onClick: () => { filePicker.current?.click(); }, children: uploading ? t('humanSettingsUploading') : hasAvatar ? t('humanSettingsReplace') : t('humanSettingsUpload') }), hasAvatar && _jsx(Button, { disabled: uploading, onClick: () => { void removeAvatar(); }, children: t('humanSettingsRemoveAvatar') })] })] })] }), _jsx(EnvironmentCheck, { t: t, environment: props.environment }), _jsxs("div", { className: css.footnote, children: [_jsx("span", { children: t('humanSettingsVersion', { version: profile.version ?? '' }) }), _jsx("span", { "aria-hidden": "true", children: "\u00B7" }), _jsx("a", { className: css.link, href: profile.repoUrl ?? '', target: "_blank", rel: "noreferrer", children: "GitHub" }), profile.updateAvailable && profile.latestVersion !== undefined
113
116
  ? _jsx("a", { className: css.link, href: `${profile.repoUrl ?? ''}/releases`, target: "_blank", rel: "noreferrer", children: t('humanSettingsUpdateAvailable', { version: profile.latestVersion }) })
114
117
  : null] }), emptyName && _jsx("p", { className: css.notice, children: t('humanSettingsNameEmpty') }), notice === null ? null : _jsx("p", { className: css.notice, role: "alert", children: notice })] }));
115
118
  }
@@ -230,11 +230,6 @@ function AgentRow({ workspaceId, leaveWorkspace, status, current, updateMember,
230
230
  return;
231
231
  }
232
232
  if (result.value.status.availability === 'unavailable') {
233
- const diagnostic = result.value.status.diagnostic;
234
- if (diagnostic?.class === 'session-refused' && diagnostic.remediable === false) {
235
- setRowAlert(t('restartRefusedNoRestart', { detail: diagnosticText(result.value.status) }));
236
- return;
237
- }
238
233
  setRowAlert(t('restartStillUnavailable', { diagnostic: diagnosticText(result.value.status) || t('statusUnavailable') }));
239
234
  return;
240
235
  }
@@ -7,7 +7,7 @@ export declare function diagnosticText(status: Pick<AgentTeamClientMemberStatus,
7
7
  /**
8
8
  * Whether the restart action can help an unavailable Member: it heals
9
9
  * transient and repairable failures, but not a transient rollover window
10
- * (which resolves on its own) or a refusal already proven non-remediable.
10
+ * (which resolves on its own).
11
11
  */
12
12
  export declare function restartOffered(status: AgentTeamClientMemberStatus): boolean;
13
13
  /** Shared presence → indicator mapping for dots and avatar badges. */
@@ -1 +1 @@
1
- {"version":3,"file":"TeamPresenceDot.d.ts","sourceRoot":"","sources":["../../../src/client/TeamPresenceDot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAG3D,wBAAgB,aAAa,CAAC,MAAM,EAAE,2BAA2B,EAAE,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,MAAM,CAKnG;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,2BAA2B,EAAE,YAAY,CAAC,GAAG,MAAM,CAI9F;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAK3E;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,GAAG,iBAAiB,CAErG;AAED,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;IAC7C,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BASA"}
1
+ {"version":3,"file":"TeamPresenceDot.d.ts","sourceRoot":"","sources":["../../../src/client/TeamPresenceDot.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AACjF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAG3D,wBAAgB,aAAa,CAAC,MAAM,EAAE,2BAA2B,EAAE,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,MAAM,CAKnG;AAED,oHAAoH;AACpH,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,2BAA2B,EAAE,YAAY,CAAC,GAAG,MAAM,CAI9F;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAE3E;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,GAAG,iBAAiB,CAErG;AAED,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;IAC7C,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAA;CAClC,+BASA"}
@@ -18,15 +18,10 @@ export function diagnosticText(status) {
18
18
  /**
19
19
  * Whether the restart action can help an unavailable Member: it heals
20
20
  * transient and repairable failures, but not a transient rollover window
21
- * (which resolves on its own) or a refusal already proven non-remediable.
21
+ * (which resolves on its own).
22
22
  */
23
23
  export function restartOffered(status) {
24
- const diagnostic = status.diagnostic;
25
- if (diagnostic === undefined)
26
- return true;
27
- if (diagnostic.class === 'rollover')
28
- return false;
29
- return !(diagnostic.class === 'session-refused' && diagnostic.remediable === false);
24
+ return status.diagnostic?.class !== 'rollover';
30
25
  }
31
26
  /** Shared presence → indicator mapping for dots and avatar badges. */
32
27
  export function presenceDotState(presence) {
@@ -0,0 +1,65 @@
1
+ import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol';
2
+ import type { AgentTeamEnvironmentResult } from '@wowyuarm/dsh-agent-team/types';
3
+ /**
4
+ * The Client's one projection of the local environment check.
5
+ *
6
+ * Deliberately separate from the Human identity projection: this is a fact
7
+ * about the installation, not about the Human, it is read once and never
8
+ * written back, and the settings page is the only surface that renders it.
9
+ * Folding it into the identity store would make every seat that names the
10
+ * Human depend on a version comparison it has no use for.
11
+ *
12
+ * Reads are demand-driven off the first subscriber, so an ordinary conversation
13
+ * never calls the Remote. There is no retry: `undetermined` is a settled
14
+ * verdict about facts the Host could not establish, not a failed request, so a
15
+ * reader has nothing to retry.
16
+ */
17
+ /** One read of the environment check, replaced wholesale on every change. */
18
+ export interface TeamEnvironmentSnapshot {
19
+ /** `loading` until the first read settles, `ready` once it has. */
20
+ readonly status: 'loading' | 'ready';
21
+ /** The report to render; undefined until the first read settles. */
22
+ readonly report?: AgentTeamEnvironmentResult | undefined;
23
+ }
24
+ /** Read-side face the settings page binds. */
25
+ export interface TeamEnvironmentSource {
26
+ getSnapshot(): TeamEnvironmentSnapshot;
27
+ subscribe(listener: () => void): () => void;
28
+ }
29
+ /** Host call the store reads through; one loader per Client context. */
30
+ export interface TeamEnvironmentLoader {
31
+ loadEnvironment: () => Promise<RemoteResult<AgentTeamEnvironmentResult>>;
32
+ }
33
+ export declare class TeamEnvironmentCheck implements TeamEnvironmentSource {
34
+ private snapshot;
35
+ private readonly listeners;
36
+ private reading;
37
+ private readonly loader;
38
+ constructor(loader: TeamEnvironmentLoader);
39
+ readonly getSnapshot: () => TeamEnvironmentSnapshot;
40
+ /**
41
+ * Observe the check, starting the first read when nobody has read yet.
42
+ * @param listener - invoked after every snapshot replacement.
43
+ * @returns the disposer removing this listener.
44
+ */
45
+ readonly subscribe: (listener: () => void) => (() => void);
46
+ /**
47
+ * Read the Host projection. Concurrent callers share one round trip, and a
48
+ * failed read keeps the last accepted report — the block never blanks out
49
+ * over a background read.
50
+ * @returns settlement of this read (or of the read already in flight).
51
+ */
52
+ refresh(): Promise<void>;
53
+ dispose(): void;
54
+ private read;
55
+ /**
56
+ * Settle a read that produced no report, so a reader stops waiting on a
57
+ * `loading` that will never finish. A report that already stands is left
58
+ * untouched: a failed background read never blanks the block.
59
+ */
60
+ private fail;
61
+ private commit;
62
+ }
63
+ /** Subscribe one rendered block to the environment check. */
64
+ export declare function useEnvironmentCheck(environment: TeamEnvironmentSource): TeamEnvironmentSnapshot;
65
+ //# sourceMappingURL=environment-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment-check.d.ts","sourceRoot":"","sources":["../../../src/client/environment-check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAA;AAEhF;;;;;;;;;;;;;GAaG;AAEH,6EAA6E;AAC7E,MAAM,WAAW,uBAAuB;IACtC,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAA;IACpC,oEAAoE;IACpE,QAAQ,CAAC,MAAM,CAAC,EAAE,0BAA0B,GAAG,SAAS,CAAA;CACzD;AAED,8CAA8C;AAC9C,MAAM,WAAW,qBAAqB;IACpC,WAAW,IAAI,uBAAuB,CAAA;IACtC,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;CAC5C;AAED,wEAAwE;AACxE,MAAM,WAAW,qBAAqB;IACpC,eAAe,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,0BAA0B,CAAC,CAAC,CAAA;CACzE;AAID,qBAAa,oBAAqB,YAAW,qBAAqB;IAChE,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAClD,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;gBAElC,MAAM,EAAE,qBAAqB;IAIzC,QAAQ,CAAC,WAAW,QAAO,uBAAuB,CAAiB;IAEnE;;;;OAIG;IACH,QAAQ,CAAC,SAAS,GAAI,UAAU,MAAM,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC,CAIxD;IAED;;;;;OAKG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IASxB,OAAO,IAAI,IAAI;YAID,IAAI;IAkBlB;;;;OAIG;IACH,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,MAAM;CAIf;AAED,6DAA6D;AAC7D,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,qBAAqB,GAAG,uBAAuB,CAE/F"}
@@ -0,0 +1,78 @@
1
+ import { useSyncExternalStore } from 'react';
2
+ const INITIAL = { status: 'loading' };
3
+ export class TeamEnvironmentCheck {
4
+ snapshot = INITIAL;
5
+ listeners = new Set();
6
+ reading;
7
+ loader;
8
+ constructor(loader) {
9
+ this.loader = loader;
10
+ }
11
+ getSnapshot = () => this.snapshot;
12
+ /**
13
+ * Observe the check, starting the first read when nobody has read yet.
14
+ * @param listener - invoked after every snapshot replacement.
15
+ * @returns the disposer removing this listener.
16
+ */
17
+ subscribe = (listener) => {
18
+ this.listeners.add(listener);
19
+ if (this.snapshot.status === 'loading' && this.reading === undefined)
20
+ void this.refresh();
21
+ return () => { this.listeners.delete(listener); };
22
+ };
23
+ /**
24
+ * Read the Host projection. Concurrent callers share one round trip, and a
25
+ * failed read keeps the last accepted report — the block never blanks out
26
+ * over a background read.
27
+ * @returns settlement of this read (or of the read already in flight).
28
+ */
29
+ refresh() {
30
+ if (this.reading !== undefined)
31
+ return this.reading;
32
+ const reading = this.read().finally(() => {
33
+ if (this.reading === reading)
34
+ this.reading = undefined;
35
+ });
36
+ this.reading = reading;
37
+ return reading;
38
+ }
39
+ dispose() {
40
+ this.listeners.clear();
41
+ }
42
+ async read() {
43
+ let report;
44
+ try {
45
+ const result = await this.loader.loadEnvironment();
46
+ if (!result.ok) {
47
+ this.fail();
48
+ return;
49
+ }
50
+ report = result.value;
51
+ }
52
+ catch {
53
+ // A dropped connection surfaces as a thrown carrier error, not a result:
54
+ // both are read failures and both keep whatever report already stands.
55
+ this.fail();
56
+ return;
57
+ }
58
+ this.commit({ status: 'ready', report });
59
+ }
60
+ /**
61
+ * Settle a read that produced no report, so a reader stops waiting on a
62
+ * `loading` that will never finish. A report that already stands is left
63
+ * untouched: a failed background read never blanks the block.
64
+ */
65
+ fail() {
66
+ if (this.snapshot.report === undefined)
67
+ this.commit({ status: 'ready' });
68
+ }
69
+ commit(snapshot) {
70
+ this.snapshot = snapshot;
71
+ for (const listener of this.listeners)
72
+ listener();
73
+ }
74
+ }
75
+ /** Subscribe one rendered block to the environment check. */
76
+ export function useEnvironmentCheck(environment) {
77
+ return useSyncExternalStore(environment.subscribe, environment.getSnapshot, environment.getSnapshot);
78
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AA6CnE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAK5C,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAEnD,YAAY,EAAE,QAAQ,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC9F,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAIhD,eAAO,MAAM,MAAM,UAElB,CAAA;AAuBD,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,IAAI,EAAE,OAAO,CAAA;KACd;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,cAAc,EAAE,cAAc,CAAA;QAC9B,UAAU,EAAE,cAAc,CAAA;KAC3B;CACF;AAsQD,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AA8CnE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAK5C,OAAO,EAAU,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAEnD,YAAY,EAAE,QAAQ,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AAC9F,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAIhD,eAAO,MAAM,MAAM,UAElB,CAAA;AAuBD,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,IAAI,EAAE,OAAO,CAAA;KACd;CACF;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,cAAc,EAAE,cAAc,CAAA;QAC9B,UAAU,EAAE,cAAc,CAAA;KAC3B;CACF;AA8QD,wBAAsB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
@@ -1,6 +1,7 @@
1
1
  import agentTeamRemote from '@wowyuarm/dsh-agent-team/remote';
2
2
  import { HumanSettingsSection } from "./HumanSettingsSection.js";
3
3
  import { TeamHumanIdentity } from "./human-identity.js";
4
+ import { TeamEnvironmentCheck } from "./environment-check.js";
4
5
  import { bytesToBase64 } from "./attachment-preview.js";
5
6
  import { TeamNavigation } from "./navigation.js";
6
7
  import { TeamChangeStream, TeamReadStream } from "./team-changes.js";
@@ -160,10 +161,17 @@ function applyUi(ctx) {
160
161
  return `data:${result.value.mediaType};base64,${result.value.bytesBase64}`;
161
162
  },
162
163
  });
164
+ // The local environment check: a fact about this installation rather than
165
+ // about the Human, so it is its own projection and never a field of the
166
+ // identity above. Read once, on the first subscriber, and never written back.
167
+ const environment = new TeamEnvironmentCheck({
168
+ loadEnvironment: () => ctx.remote.agentTeam.environment({}),
169
+ });
163
170
  ctx.effect(() => () => {
164
171
  navigation.dispose();
165
172
  drafts.dispose();
166
173
  humanIdentity.dispose();
174
+ environment.dispose();
167
175
  void disposeNavigation();
168
176
  void disposeDrafts();
169
177
  }, 'agent-team: navigation service');
@@ -250,6 +258,7 @@ function applyUi(ctx) {
250
258
  locale: NS,
251
259
  inject: () => ({
252
260
  identity: humanIdentity,
261
+ environment,
253
262
  saveName: async (name) => {
254
263
  const saved = await ctx.remote.agentTeam.setHumanProfile({ name });
255
264
  if (!saved.ok)
@@ -64,13 +64,11 @@ export declare const zh: {
64
64
  readonly resumeAgent: "恢复";
65
65
  readonly restartAgent: "重启";
66
66
  readonly restartStillUnavailable: "重启已执行,成员仍不可用:{diagnostic}";
67
- readonly restartRefusedNoRestart: "会话日志被确定拒绝,修复无可用项,重启无法解决:{detail}";
68
67
  readonly restartFailed: "重启执行失败:{message}";
69
68
  readonly archiveAgent: "归档";
70
69
  readonly archiveAgentTitle: "归档 Agent:{name}";
71
70
  readonly archiveAgentNotice: "将把 {name} 从所有列表收起:会话与私有记忆保留在磁盘上、活跃 Claim 会释放,但暂无恢复入口。";
72
71
  readonly archiveAgentConfirm: "归档";
73
- readonly archiveAgentFailed: "归档失败:{message}";
74
72
  readonly archiveChannel: "归档频道";
75
73
  readonly archiveChannelTitle: "归档频道:{name}";
76
74
  readonly archiveChannelNotice: "将把 {name} 及其全部讨论从所有列表收起:数据保留、所有成员在此频道的活跃 Claim 会释放,但暂无恢复入口。";
@@ -133,13 +131,21 @@ export declare const zh: {
133
131
  readonly humanSettingsUnavailable: "资料读不出来:{message}";
134
132
  readonly humanSettingsVersion: "版本 {version}";
135
133
  readonly humanSettingsUpdateAvailable: "有新版本 {version},去查看发布说明";
134
+ readonly environmentOkTitle: "在支持范围内";
135
+ readonly environmentOkDetail: "正在运行的 DSH {version} 在我们声明的支持范围内。";
136
+ readonly environmentOutOfRangeTitle: "不在支持范围内";
137
+ readonly environmentOutOfRangeDetail: "正在运行的 DSH {version} 不在我们声明的支持范围内——这套组合未经我们认证,可能出问题。";
138
+ readonly environmentRange: "支持范围:{lower} 起、{upper} 之前。";
139
+ readonly environmentTested: "我们实测认证的组合:Agent Team {bundle} × DSH {dsh}。";
140
+ readonly environmentUndeterminedTitle: "无法判定运行环境";
141
+ readonly environmentUndeterminedDetail: "读不到正在运行的 DSH 版本,或无法确定我们的支持范围,因此不做判断。";
142
+ readonly environmentReleaseNotes: "查看发布说明";
136
143
  readonly taskStatusTodo: "待处理";
137
144
  readonly taskStatusInProgress: "进行中";
138
145
  readonly taskStatusInReview: "待验收";
139
146
  readonly taskStatusDone: "已完成";
140
147
  readonly taskStatusClosed: "已关闭";
141
148
  readonly taskLabel: "Task #{number}";
142
- readonly taskPending: "Task …";
143
149
  readonly openTask: "打开 Task #{number}";
144
150
  readonly openThread: "打开讨论";
145
151
  readonly openTaskUnread: "打开 Task #{number}({count} 条新动态)";
@@ -206,7 +212,6 @@ export declare const zh: {
206
212
  readonly activityReopened: "{actor} 重新打开了此 Task";
207
213
  readonly mentionConfirmation: "提及未关注成员需要确认,再次发送以继续";
208
214
  readonly memberNotFollowing: "这些成员还未关注此 Thread:{ids}";
209
- readonly sendFailedKind: "无法发送消息({kind})";
210
215
  readonly unreadRequired: "请先读取 {count} 条未读更新,再继续修改。";
211
216
  readonly staleRevision: "Thread 已发生变化,请按最新状态重试。";
212
217
  };
@@ -276,13 +281,11 @@ export declare const en: {
276
281
  readonly resumeAgent: "Resume";
277
282
  readonly restartAgent: "Restart";
278
283
  readonly restartStillUnavailable: "Restart ran, but the Member is still unavailable: {diagnostic}";
279
- readonly restartRefusedNoRestart: "The session log is deterministically refused with nothing repairable; restarting cannot fix it: {detail}";
280
284
  readonly restartFailed: "Restart failed: {message}";
281
285
  readonly archiveAgent: "Archive";
282
286
  readonly archiveAgentTitle: "Archive Agent: {name}";
283
287
  readonly archiveAgentNotice: "This hides {name} from every list: the session log and private memory stay on disk and active Claims release, but there is no restore entry point yet.";
284
288
  readonly archiveAgentConfirm: "Archive";
285
- readonly archiveAgentFailed: "Failed to archive: {message}";
286
289
  readonly archiveChannel: "Archive Channel";
287
290
  readonly archiveChannelTitle: "Archive Channel: {name}";
288
291
  readonly archiveChannelNotice: "This hides {name} and all of its discussions from every list: the data stays, every Member's active Claims in this Channel release, but there is no restore entry point yet.";
@@ -345,13 +348,21 @@ export declare const en: {
345
348
  readonly humanSettingsUnavailable: "The profile could not be read: {message}";
346
349
  readonly humanSettingsVersion: "Version {version}";
347
350
  readonly humanSettingsUpdateAvailable: "New version {version} available — see the release notes";
351
+ readonly environmentOkTitle: "Within the supported range";
352
+ readonly environmentOkDetail: "The running DSH {version} is within the range we declare support for.";
353
+ readonly environmentOutOfRangeTitle: "Outside the supported range";
354
+ readonly environmentOutOfRangeDetail: "The running DSH {version} is outside the range we declare support for — we have not certified this combination and it may misbehave.";
355
+ readonly environmentRange: "Support range: from {lower} up to, but not including, {upper}.";
356
+ readonly environmentTested: "Certified combination: Agent Team {bundle} × DSH {dsh}.";
357
+ readonly environmentUndeterminedTitle: "Environment cannot be determined";
358
+ readonly environmentUndeterminedDetail: "The running DSH version could not be read, or our support range could not be established, so no judgement is made.";
359
+ readonly environmentReleaseNotes: "See the release notes";
348
360
  readonly taskStatusTodo: "To do";
349
361
  readonly taskStatusInProgress: "In progress";
350
362
  readonly taskStatusInReview: "In review";
351
363
  readonly taskStatusDone: "Done";
352
364
  readonly taskStatusClosed: "Closed";
353
365
  readonly taskLabel: "Task #{number}";
354
- readonly taskPending: "Task …";
355
366
  readonly openTask: "Open Task #{number}";
356
367
  readonly openThread: "Open thread";
357
368
  readonly openTaskUnread: "Open Task #{number} ({count} new updates)";
@@ -418,7 +429,6 @@ export declare const en: {
418
429
  readonly activityReopened: "{actor} reopened this Task";
419
430
  readonly mentionConfirmation: "Mentioning an unfollowed member requires confirmation; send again to continue";
420
431
  readonly memberNotFollowing: "These Members do not follow this Thread yet: {ids}";
421
- readonly sendFailedKind: "Unable to send message ({kind})";
422
432
  readonly unreadRequired: "Read {count} unread update(s) before changing this Thread.";
423
433
  readonly staleRevision: "This Thread changed; retry using the current state.";
424
434
  };
@@ -1 +1 @@
1
- {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuNL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqNL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+NL,CAAA;AAEV,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0NL,CAAA;AAEV,MAAM,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE,CAAA"}
@@ -64,13 +64,11 @@ export const zh = {
64
64
  resumeAgent: '恢复',
65
65
  restartAgent: '重启',
66
66
  restartStillUnavailable: '重启已执行,成员仍不可用:{diagnostic}',
67
- restartRefusedNoRestart: '会话日志被确定拒绝,修复无可用项,重启无法解决:{detail}',
68
67
  restartFailed: '重启执行失败:{message}',
69
68
  archiveAgent: '归档',
70
69
  archiveAgentTitle: '归档 Agent:{name}',
71
70
  archiveAgentNotice: '将把 {name} 从所有列表收起:会话与私有记忆保留在磁盘上、活跃 Claim 会释放,但暂无恢复入口。',
72
71
  archiveAgentConfirm: '归档',
73
- archiveAgentFailed: '归档失败:{message}',
74
72
  archiveChannel: '归档频道',
75
73
  archiveChannelTitle: '归档频道:{name}',
76
74
  archiveChannelNotice: '将把 {name} 及其全部讨论从所有列表收起:数据保留、所有成员在此频道的活跃 Claim 会释放,但暂无恢复入口。',
@@ -133,13 +131,24 @@ export const zh = {
133
131
  humanSettingsUnavailable: '资料读不出来:{message}',
134
132
  humanSettingsVersion: '版本 {version}',
135
133
  humanSettingsUpdateAvailable: '有新版本 {version},去查看发布说明',
134
+ // The environment check. The support line is stated in words, never as a bare
135
+ // semver range, and the tested-combination line prints only versions the Host
136
+ // could derive — the page adds no version of its own.
137
+ environmentOkTitle: '在支持范围内',
138
+ environmentOkDetail: '正在运行的 DSH {version} 在我们声明的支持范围内。',
139
+ environmentOutOfRangeTitle: '不在支持范围内',
140
+ environmentOutOfRangeDetail: '正在运行的 DSH {version} 不在我们声明的支持范围内——这套组合未经我们认证,可能出问题。',
141
+ environmentRange: '支持范围:{lower} 起、{upper} 之前。',
142
+ environmentTested: '我们实测认证的组合:Agent Team {bundle} × DSH {dsh}。',
143
+ environmentUndeterminedTitle: '无法判定运行环境',
144
+ environmentUndeterminedDetail: '读不到正在运行的 DSH 版本,或无法确定我们的支持范围,因此不做判断。',
145
+ environmentReleaseNotes: '查看发布说明',
136
146
  taskStatusTodo: '待处理',
137
147
  taskStatusInProgress: '进行中',
138
148
  taskStatusInReview: '待验收',
139
149
  taskStatusDone: '已完成',
140
150
  taskStatusClosed: '已关闭',
141
151
  taskLabel: 'Task #{number}',
142
- taskPending: 'Task …',
143
152
  openTask: '打开 Task #{number}',
144
153
  openThread: '打开讨论',
145
154
  openTaskUnread: '打开 Task #{number}({count} 条新动态)',
@@ -210,7 +219,6 @@ export const zh = {
210
219
  activityReopened: '{actor} 重新打开了此 Task',
211
220
  mentionConfirmation: '提及未关注成员需要确认,再次发送以继续',
212
221
  memberNotFollowing: '这些成员还未关注此 Thread:{ids}',
213
- sendFailedKind: '无法发送消息({kind})',
214
222
  unreadRequired: '请先读取 {count} 条未读更新,再继续修改。',
215
223
  staleRevision: 'Thread 已发生变化,请按最新状态重试。',
216
224
  };
@@ -280,13 +288,11 @@ export const en = {
280
288
  resumeAgent: 'Resume',
281
289
  restartAgent: 'Restart',
282
290
  restartStillUnavailable: 'Restart ran, but the Member is still unavailable: {diagnostic}',
283
- restartRefusedNoRestart: 'The session log is deterministically refused with nothing repairable; restarting cannot fix it: {detail}',
284
291
  restartFailed: 'Restart failed: {message}',
285
292
  archiveAgent: 'Archive',
286
293
  archiveAgentTitle: 'Archive Agent: {name}',
287
294
  archiveAgentNotice: 'This hides {name} from every list: the session log and private memory stay on disk and active Claims release, but there is no restore entry point yet.',
288
295
  archiveAgentConfirm: 'Archive',
289
- archiveAgentFailed: 'Failed to archive: {message}',
290
296
  archiveChannel: 'Archive Channel',
291
297
  archiveChannelTitle: 'Archive Channel: {name}',
292
298
  archiveChannelNotice: 'This hides {name} and all of its discussions from every list: the data stays, every Member\'s active Claims in this Channel release, but there is no restore entry point yet.',
@@ -349,13 +355,21 @@ export const en = {
349
355
  humanSettingsUnavailable: 'The profile could not be read: {message}',
350
356
  humanSettingsVersion: 'Version {version}',
351
357
  humanSettingsUpdateAvailable: 'New version {version} available — see the release notes',
358
+ environmentOkTitle: 'Within the supported range',
359
+ environmentOkDetail: 'The running DSH {version} is within the range we declare support for.',
360
+ environmentOutOfRangeTitle: 'Outside the supported range',
361
+ environmentOutOfRangeDetail: 'The running DSH {version} is outside the range we declare support for — we have not certified this combination and it may misbehave.',
362
+ environmentRange: 'Support range: from {lower} up to, but not including, {upper}.',
363
+ environmentTested: 'Certified combination: Agent Team {bundle} × DSH {dsh}.',
364
+ environmentUndeterminedTitle: 'Environment cannot be determined',
365
+ environmentUndeterminedDetail: 'The running DSH version could not be read, or our support range could not be established, so no judgement is made.',
366
+ environmentReleaseNotes: 'See the release notes',
352
367
  taskStatusTodo: 'To do',
353
368
  taskStatusInProgress: 'In progress',
354
369
  taskStatusInReview: 'In review',
355
370
  taskStatusDone: 'Done',
356
371
  taskStatusClosed: 'Closed',
357
372
  taskLabel: 'Task #{number}',
358
- taskPending: 'Task …',
359
373
  openTask: 'Open Task #{number}',
360
374
  openThread: 'Open thread',
361
375
  openTaskUnread: 'Open Task #{number} ({count} new updates)',
@@ -424,7 +438,6 @@ export const en = {
424
438
  activityReopened: '{actor} reopened this Task',
425
439
  mentionConfirmation: 'Mentioning an unfollowed member requires confirmation; send again to continue',
426
440
  memberNotFollowing: 'These Members do not follow this Thread yet: {ids}',
427
- sendFailedKind: 'Unable to send message ({kind})',
428
441
  unreadRequired: 'Read {count} unread update(s) before changing this Thread.',
429
442
  staleRevision: 'This Thread changed; retry using the current state.',
430
443
  };