@lmzhen/dsh-evolution-ui 0.0.0 → 0.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +6 -1
  2. package/lib/client.js +3656 -0
  3. package/lib/index.js +323 -0
  4. package/lib/types/client/index.d.ts +9 -0
  5. package/lib/types/index.d.ts +12 -0
  6. package/lib/types/panels/history/client/Panel.d.ts +27 -0
  7. package/lib/types/panels/history/client/api.d.ts +142 -0
  8. package/lib/types/panels/history/client/atoms.d.ts +73 -0
  9. package/lib/types/panels/history/client/chrome.d.ts +76 -0
  10. package/lib/types/panels/history/client/document.d.ts +71 -0
  11. package/lib/types/panels/history/client/guards.d.ts +13 -0
  12. package/lib/types/panels/history/client/ids.d.ts +3 -0
  13. package/lib/types/panels/history/client/index.d.ts +11 -0
  14. package/lib/types/panels/history/client/markdown.d.ts +56 -0
  15. package/lib/types/panels/history/client/messages.d.ts +30 -0
  16. package/lib/types/panels/history/client/styles.d.ts +5 -0
  17. package/lib/types/panels/history/host.d.ts +25 -0
  18. package/lib/types/panels/history/routes.d.ts +50 -0
  19. package/lib/types/panels/history/unit-undoable.d.ts +18 -0
  20. package/lib/types/panels/settings/DiagnosticsCard.d.ts +29 -0
  21. package/lib/types/panels/settings/ParamCard.d.ts +107 -0
  22. package/lib/types/panels/settings/PendingCard.d.ts +45 -0
  23. package/lib/types/panels/settings/RowConfigCard.d.ts +30 -0
  24. package/lib/types/panels/settings/SettingsSection.d.ts +19 -0
  25. package/lib/types/panels/settings/api.d.ts +64 -0
  26. package/lib/types/panels/settings/diagnostics-state.d.ts +28 -0
  27. package/lib/types/panels/settings/generated-about.d.ts +11 -0
  28. package/lib/types/panels/settings/generated-params.d.ts +51 -0
  29. package/lib/types/panels/settings/guards.d.ts +13 -0
  30. package/lib/types/panels/settings/index.d.ts +50 -0
  31. package/lib/types/panels/settings/messages.d.ts +134 -0
  32. package/lib/types/panels/settings/pending-state.d.ts +74 -0
  33. package/lib/types/panels/settings/seam.d.ts +178 -0
  34. package/lib/types/panels/settings/source.d.ts +88 -0
  35. package/lib/types/panels/settings/styles.d.ts +32 -0
  36. package/package.json +51 -4
@@ -0,0 +1,71 @@
1
+ /**
2
+ * The READING face: one version rendered as a document, and the rendered diff.
3
+ *
4
+ * This file is the only place that decides how a document reads (G4). The tool face (`chrome.ts`)
5
+ * picks versions and acts on them; here the rules are the reader's, and they follow the positioning
6
+ * ruling of §14.0: a document is read, not scanned — one measure, page-like spacing, no inner scroll
7
+ * (W18/W20/W21/W22). Nothing here is a control except the source/rendered choice, which belongs to
8
+ * the reader rather than to the panel's actions.
9
+ *
10
+ * The text arrives already prepared: the host strips the frontmatter block through core's
11
+ * `displayBodyOf`, because a browser half cannot import core. The RENDERED DIFF keeps the whole text
12
+ * on purpose — a diff is about what CHANGED, and a metadata change is a change.
13
+ *
14
+ * It degrades rather than blanking: when the platform's renderer cannot be reached, the exact text is
15
+ * shown instead, and the reader can still read the version.
16
+ * @module @lmzhen/dsh-evolution-ui/panels/history/client
17
+ */
18
+ import { type ReactNode } from 'react';
19
+ import type { VersionBodyRow, VersionDiffRow } from './api.ts';
20
+ import type { Copy } from './chrome.ts';
21
+ import { type MarkdownWords } from './markdown.ts';
22
+ /** What one expanded diff holds: the change, still loading, or a refusal. */
23
+ export type DiffState = {
24
+ kind: 'loading';
25
+ } | {
26
+ kind: 'ready';
27
+ diff: VersionDiffRow;
28
+ } | {
29
+ kind: 'failed';
30
+ message: string;
31
+ };
32
+ /** What one expanded preview holds. */
33
+ export type BodyState = {
34
+ kind: 'loading';
35
+ } | {
36
+ kind: 'ready';
37
+ body: VersionBodyRow;
38
+ } | {
39
+ kind: 'failed';
40
+ message: string;
41
+ };
42
+ /** What the reading face needs: the dictionary seat, plus the two words the platform renderer takes. */
43
+ export interface DocumentFace extends Copy {
44
+ readonly markdownWords: MarkdownWords;
45
+ }
46
+ /**
47
+ * One version read as a document: the platform renderer when it is there, plain text when it is not.
48
+ *
49
+ * The document is the page, not a card inside it: no border, no surface of its own and no inner
50
+ * scroll, so the pane's own scrollbar is the only one a reader meets (W20/W21). A body the host
51
+ * bounded says how much it is not showing, with both numbers (W23).
52
+ * @param props - the face and the body state to draw.
53
+ * @returns the element.
54
+ */
55
+ export declare function PreviewBody(props: {
56
+ face: DocumentFace;
57
+ body: BodyState;
58
+ }): ReactNode;
59
+ /**
60
+ * The expanded body of one row: the diff, a loading line, or the refusal.
61
+ *
62
+ * The source/rendered choice is LOCAL to this view: which row is open is the panel's business, but
63
+ * how one open diff is displayed is not, so the state does not climb into the parent.
64
+ * @param props - the face and the diff state to draw.
65
+ * @returns the element.
66
+ */
67
+ export declare function DiffBody(props: {
68
+ face: DocumentFace;
69
+ diff: DiffState;
70
+ }): ReactNode;
71
+ //# sourceMappingURL=document.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Is this a non-null, non-array object (what JSON calls an object)?
3
+ * @param value - the value to test.
4
+ * @returns whether it is a plain object.
5
+ */
6
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
7
+ /**
8
+ * Read a value as a record, or undefined when it is not one.
9
+ * @param value - the value to read.
10
+ * @returns the value typed as a record, or undefined.
11
+ */
12
+ export declare function asRecord(value: unknown): Record<string, unknown> | undefined;
13
+ //# sourceMappingURL=guards.d.ts.map
@@ -0,0 +1,3 @@
1
+ export declare const PANEL_ID = "skill-history";
2
+ export declare const PANEL_ORDER = 35;
3
+ //# sourceMappingURL=ids.d.ts.map
@@ -0,0 +1,11 @@
1
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
2
+ /** Required client services: the slot registry and the locale seat. */
3
+ export declare const inject: string[];
4
+ /** Row order inside the global panel list (beside the platform's own rows). */
5
+ export declare const PANEL_ORDER = 35;
6
+ /**
7
+ * Register the locale namespace, the panel row and the panel body.
8
+ * @param ctx - the client cordis context.
9
+ */
10
+ export declare function apply(ctx: ClientContext): void;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,56 @@
1
+ /** The three localized words the platform renderer needs; the face owns them. */
2
+ export interface MarkdownWords {
3
+ readonly copy: string;
4
+ readonly copied: string;
5
+ /** The heading of the generated footnote section. */
6
+ readonly footnotes: string;
7
+ }
8
+ /** Copy-button labels forwarded to fenced code blocks. */
9
+ interface MarkdownCodeLabels {
10
+ copyLabel: string;
11
+ copiedLabel: string;
12
+ }
13
+ /** Localized Markdown chrome: every field the platform component requires. */
14
+ interface MarkdownLabels {
15
+ code: MarkdownCodeLabels;
16
+ footnotes: string;
17
+ }
18
+ /** What the renderer reads; the streaming and mention knobs are not used by this panel. */
19
+ interface MarkdownTextProps {
20
+ text: string;
21
+ labels: MarkdownLabels;
22
+ }
23
+ /** The component as the module table hands it over. */
24
+ type MarkdownTextComponent = (props: MarkdownTextProps) => unknown;
25
+ /** One render attempt: the element, or the news that this deployment has no renderer. */
26
+ export type MarkdownRender = {
27
+ readonly ok: true;
28
+ readonly node: unknown;
29
+ } | {
30
+ readonly ok: false;
31
+ };
32
+ /**
33
+ * The renderer a module row carries, when it carries one.
34
+ *
35
+ * A React component type is NOT always a function: the platform's own `MarkdownText` is
36
+ * `memo(function MarkdownText …)`, and `memo` returns an OBJECT. A `typeof === 'function'` test
37
+ * therefore rejected the real renderer and silently degraded every view to its source — exactly
38
+ * what 0.14.0 shipped (measured on the installed panel 2026-09-28: `[预览]` and the rendered diff
39
+ * both fell back). The accepted domain is React's element-type domain: a function, or a non-null
40
+ * object it can mount. `tests/markdown.client.spec.ts` pins all four cases.
41
+ * @param row - what the client module table handed over.
42
+ * @returns the component, or undefined when the row carries none.
43
+ */
44
+ export declare function rendererOf(row: {
45
+ MarkdownText?: unknown;
46
+ }): MarkdownTextComponent | undefined;
47
+ /**
48
+ * Render one Markdown document to an element tree.
49
+ * @param text - the Markdown source (already bounded by the caller).
50
+ * @param words - the localized Markdown chrome.
51
+ * @returns the element, or `{ ok: false }` when the platform renderer is not reachable (the caller
52
+ * then keeps its own source view: a missing renderer degrades the view, never the panel).
53
+ */
54
+ export declare function renderMarkdown(text: string, words: MarkdownWords): MarkdownRender;
55
+ export {};
56
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Panel copy, in a zh/en dictionary registered through the platform’s locale seat.
3
+ *
4
+ * Client copy is locale-owned: the entry label, the group headings, the actions, the version facts
5
+ * (action words, relative time, deltas) and the status lines all resolve here, and the panel carries
6
+ * no literal string of its own. Facts come from the host; only the WORDS live here.
7
+ * @module @lmzhen/dsh-evolution-ui/panels/history/client
8
+ */
9
+ /** The locale namespace this bundle registers. */
10
+ export declare const NS = "evolution-skill-history";
11
+ /** Chinese dictionary. */
12
+ export declare const zh: Record<string, string>;
13
+ /** English dictionary: the same keys, or the panel falls back to the key itself. */
14
+ export declare const en: Record<string, string>;
15
+ /**
16
+ * One message without the locale seat (the fallback path, and what a spec reads).
17
+ * @param language - which dictionary to read.
18
+ * @param key - the message key.
19
+ * @returns the copy, or the key itself when neither dictionary carries it.
20
+ */
21
+ export declare function message(key: string, language?: 'zh' | 'en'): string;
22
+ /**
23
+ * Fill one TEMPLATE’s `{n}` slots. The seat resolves the key, this fills it, so the panel needs
24
+ * only the seat plus this rule and never learns which language it is rendering.
25
+ * @param template - the copy, with `{slot}` placeholders.
26
+ * @param values - the substitutions, keyed by the slot name inside the braces.
27
+ * @returns the filled copy.
28
+ */
29
+ export declare function fill(template: string, values: Record<string, string | number>): string;
30
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1,5 @@
1
+ /** Tag id that makes the injection idempotent. */
2
+ export declare const CSS_TAG_ID = "@lmzhen/dsh-evolution-ui/panel.css";
3
+ /** The stylesheet the panel injects once. */
4
+ export declare const CSS: string;
5
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Host half of the skill-history surface: it mounts the six routes the sidebar panel reads and
3
+ * writes, and it owns nothing else.
4
+ *
5
+ * W6/G4: the carrier is the platform's Host connection data plane. `registerHostRoutes` waits on the
6
+ * `connection` service (it may apply after this row), registers via one owner effect and captures the
7
+ * DecisionAudit there; the old webServer + loopback fence path is gone.
8
+ *
9
+ * The version FACTS come from evolution-core (which artifact a version holds, how the body chain and
10
+ * the support-file chain split) and the only write is the curator's undo, so this row carries no state
11
+ * of its own: unloading it removes the routes and leaves the feature's data untouched.
12
+ * @module @lmzhen/dsh-evolution-ui/panels/history
13
+ */
14
+ import type { Context } from '@deepseek-ai/cordis';
15
+ export declare const name = "evolution-skill-history";
16
+ /** No declared service: a headless profile must not leave a pending row, and the curator is resolved
17
+ * per request; `connection` is waited on inside registerHostRoutes, not demanded here. */
18
+ export declare const inject: string[];
19
+ /**
20
+ * Mount the routes as ONE owner effect (disposers run on unload and on HMR). A profile whose host has
21
+ * no connection service simply never runs the callback — inert, never pending.
22
+ * @param ctx - the host context; the connection and curator arrive through it.
23
+ */
24
+ export declare function apply(ctx: Context): void;
25
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The skill-history HTTP surface: six exact Fetch routes over the curator's read/write seam (five
3
+ * reads plus the one write).
4
+ *
5
+ * W6/G4: the carrier is the platform's Host connection data plane — the fence, browser auth and
6
+ * owner-only admission are applied by the platform BEFORE `fetch(request)` runs, so this module has
7
+ * no 403/401 branch. The wire envelope the browser half reads is unchanged.
8
+ *
9
+ * Layering: this module maps a route to a USE CASE and does nothing else. "Which artifact does this
10
+ * version hold" and "how do the two chains split" live in evolution-core; the only write is
11
+ * curator.undo. The panel never writes the skill tree itself.
12
+ * @module @lmzhen/dsh-evolution-ui/panels/history/routes
13
+ */
14
+ import type { Context } from '@deepseek-ai/cordis';
15
+ import type { ConnectionFetchRouteLike, DecisionAudit } from '@lmzhen/dsh-evolution-core/http-routes';
16
+ /** Route paths: the ONE declaration lives in core (W1); the client constants are generated from it. */
17
+ export declare const SKILL_HISTORY_ROUTES: {
18
+ readonly skills: "/api/dsh-evolution/skill-history/skills";
19
+ readonly versions: "/api/dsh-evolution/skill-history/versions";
20
+ readonly diff: "/api/dsh-evolution/skill-history/versions/diff";
21
+ readonly body: "/api/dsh-evolution/skill-history/versions/body";
22
+ readonly undo: "/api/dsh-evolution/skill-history/undo";
23
+ readonly health: "/api/dsh-evolution/skill-history/health";
24
+ };
25
+ /**
26
+ * How much of one version's body the read route hands back. A bound on the ANSWER, not on what the
27
+ * deployment may store: a long skill arrives as its head plus `truncated`, so the reader is told.
28
+ */
29
+ export declare const MAX_BODY_CHARS = 20000;
30
+ /** The curator surface the routes read: history() and the library listing, undo() as the only write. */
31
+ export type CuratorFace = Pick<Context['evolutionCurator'], 'history' | 'undo' | 'undoUnit' | 'skills'>;
32
+ /**
33
+ * What the handlers resolve PER REQUEST.
34
+ *
35
+ * The curator is looked up late, not captured: a profile that mounts these routes before the curator
36
+ * (or without it) answers the family's own E-302 sentence instead of throwing, which is how every
37
+ * other optional-service consumer in this family behaves.
38
+ */
39
+ export interface RouteServices {
40
+ readonly getCurator: () => CuratorFace | undefined;
41
+ }
42
+ /**
43
+ * Build the six routes over the curator seam.
44
+ * @param services - the host services the handlers read.
45
+ * @param _audit - the registration audit (read routes record nothing; undo's decision stays the
46
+ * curator's own — W6 keeps the ledger to the approval surface).
47
+ * @returns the route list for `registerHostRoutes`.
48
+ */
49
+ export declare function makeSkillHistoryRoutes(services: RouteServices, _audit: DecisionAudit): ConnectionFetchRouteLike[];
50
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * G3b: undoability is a property of the UNIT, not of one entry.
3
+ *
4
+ * Every entry of a unit shares the same live body, so "is this undoable" must answer the same for all
5
+ * of them; computing it per entry made the body row say `false` (already current) while a support row
6
+ * of the SAME transaction said `true` — two entrances to one unit in one panel.
7
+ *
8
+ * Entries without a unit id keep the per-entry answer (they are their own singleton unit).
9
+ */
10
+ import { type SkillVersion } from '@lmzhen/dsh-evolution-core';
11
+ /** @param members - every entry that shares the unit (content and support chains together).
12
+ * @param liveHash - hash of the live body, or null when the skill is not readable.
13
+ * @returns one flag per unit id; unknown ids fall back to the per-entry rule. */
14
+ export declare function unitUndoableFlags(members: readonly SkillVersion[], liveHash: string | null): Map<string, boolean>;
15
+ /** @param entry - the entry being rendered. @param flags - the unit flags from {@link unitUndoableFlags}.
16
+ * @param liveHash - hash of the live body. @returns the row's `undoable` value. */
17
+ export declare function undoableFor(entry: SkillVersion, flags: Map<string, boolean>, liveHash: string | null): boolean | undefined;
18
+ //# sourceMappingURL=unit-undoable.d.ts.map
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The diagnostics card (W7 S7): the settings face of the SAME DiagnosticsView the CLI and the
3
+ * `/api/dsh-evolution/diagnostics` route answer.
4
+ *
5
+ * Read-only by construction: it fetches once on mount and only refetches on an explicit Refresh; a
6
+ * failed read renders the shared FailureBlock with the command-face fallback. The client owns no
7
+ * key list and no status vocabulary: it renders the host view's frozen runtime rows and leads with
8
+ * a plain-language summary. The view's documentation facts are a CLI/JSON concern and are
9
+ * deliberately NOT rendered here (0.27.2 real-machine feedback: a settings page is not a spec
10
+ * sheet; the runtime window is the whole reading).
11
+ * @module @lmzhen/dsh-evolution-ui/panels/settings/client/DiagnosticsCard
12
+ */
13
+ import { type ReactNode } from 'react';
14
+ import type { DiagnosticsApi } from './diagnostics-state.ts';
15
+ import type { FallbackHint } from '@lmzhen/dsh-evolution-client-kit/generated/contracts';
16
+ import type { MessageKey } from './messages.ts';
17
+ /** Injected face: the copy seat, the one host call, and this surface's command fallback. */
18
+ export interface DiagnosticsCardFace {
19
+ t: (key: MessageKey, values?: Readonly<Record<string, string | number>>) => string;
20
+ api: DiagnosticsApi;
21
+ fallback?: FallbackHint | undefined;
22
+ }
23
+ /**
24
+ * Render the card.
25
+ * @param props - the copy seat, the host call and the command fallback.
26
+ * @returns the card.
27
+ */
28
+ export declare function DiagnosticsCard(props: DiagnosticsCardFace): ReactNode;
29
+ //# sourceMappingURL=DiagnosticsCard.d.ts.map
@@ -0,0 +1,107 @@
1
+ /**
2
+ * One namespace's parameter card.
3
+ *
4
+ * Structural local types on purpose: this package is distributed outside the
5
+ * platform repository and a value import of another plugin is forbidden, so the
6
+ * settings scope and its snapshot are declared by the shape the renderer hands
7
+ * over (\`getSnapshot\`/\`subscribe\`, status/value/user/writable).
8
+ *
9
+ * header (namespace title, change count, chevron), then one block per field —
10
+ * header (namespace title, change count, chevron), then one block per field —
11
+ * label with its unit and source chip, a control HOLDING THE CURRENT VALUE, the
12
+ * Chinese hint — and one 放弃修改/保存 pair at the card's foot. The control is
13
+ * typed from the registry (\`control\`), so booleans are switches, enums are
14
+ * selects and numbers are numeric inputs with the unit shown beside the label.
15
+ */
16
+ import { type ReactNode } from 'react';
17
+ import type { ClientParamField } from './generated-params.ts';
18
+ import { type MessageKey } from './messages.ts';
19
+ import type { ParamSectionSnapshot, ParamSectionSource, SettingsPathOpLike } from './seam.ts';
20
+ /**
21
+ * Injected face: plain data and callbacks, plus the hook seat.
22
+ *
23
+ * The `hooks` compartment belongs to the shell, not to the component: the
24
+ * renderer binds its entries to `use<Name>` props and omits `hooks` from what
25
+ * the component receives. A card that reads `props.hooks` therefore reads a prop
26
+ * that never exists.
27
+ */
28
+ export interface ParamCardFace {
29
+ namespace: string;
30
+ fields: readonly ClientParamField[];
31
+ t: (key: MessageKey, values?: Readonly<Record<string, string | number>>) => string;
32
+ /** ONE call per save, carrying every dirty field as one op list (T5-01/A56). The returned boolean IS
33
+ * the Host's verdict (contract C2/G5): `true` = accepted, `false` = refused after its recovery read. */
34
+ mutateOnce: (ops: readonly SettingsParamOp[]) => Promise<boolean>;
35
+ clear: (field: string) => Promise<boolean>;
36
+ hooks: {
37
+ paramSection: ParamSectionSource;
38
+ };
39
+ }
40
+ /**
41
+ * Props the renderer binds for one card: the inject face minus its hook compartment,
42
+ * plus the seats bound from it. Spelled the way the shell derives it, so reaching for
43
+ * `props.hooks` fails the type check instead of failing at runtime.
44
+ */
45
+ export type ParamCardProps = Omit<ParamCardFace, 'hooks'> & {
46
+ /** Bound from \`hooks.paramSection\` by the renderer. */
47
+ readonly useParamSection: <T>(selector: (state: ParamSectionSnapshot) => T) => T;
48
+ };
49
+ /** The op list a save hands to the seat — the seam's own shape, never a second vocabulary. */
50
+ export type SettingsParamOp = SettingsPathOpLike;
51
+ /**
52
+ * The NAMESPACE-RELATIVE key of one registry field.
53
+ *
54
+ * The E3 registry writes family ids in canonical form (`evolution-approval.pendingTtlMs`),
55
+ * while the platform settings seat speaks a namespace's own field keys (`pendingTtlMs`) —
56
+ * its snapshot user layer, its base and its op paths are all relative to the namespace. Sending
57
+ * the canonical id as an op path makes the Host refuse the write
58
+ * ("Config field evolution-approval.pendingTtlMs is not volatile", measured 2026-10-19), so the
59
+ * card translates once, here, and every read/write goes through it.
60
+ * @param namespace - the settings namespace (Loader row id) the card writes.
61
+ * @param field - one generated field.
62
+ * @returns the field's key inside that namespace.
63
+ */
64
+ export declare function fieldKeyOf(namespace: string, field: ClientParamField): string;
65
+ /**
66
+ * U-4: whether one field's CURRENT text is a value the Host can take. The controls constrain their own
67
+ * domains (a number input sanitizes, a select only offers listed values), so the reachable case is a
68
+ * value the registry no longer lists — carried in the user layer and re-staged by any other edit.
69
+ * @param field - the generated field.
70
+ * @param text - the text the control holds right now.
71
+ * @param peer - U-4: the text the row this field declares `atLeast` against currently holds (absent
72
+ * when the field declares no relation, or when that row is not on this card).
73
+ * @returns the message key explaining the refusal, or null when the value is acceptable.
74
+ */
75
+ export declare function invalidReason(field: ClientParamField, text: string, peer?: string): MessageKey | null;
76
+ /**
77
+ * Render one namespace's card.
78
+ * @param props - the card data, its callbacks, and the bound section hook.
79
+ * @returns the card.
80
+ */
81
+ /** Props of the shared body: the card's own data plus the row state it renders. */
82
+ export interface ParamCardViewProps {
83
+ namespace: string;
84
+ fields: readonly ClientParamField[];
85
+ t: (key: MessageKey, values?: Readonly<Record<string, string | number>>) => string;
86
+ /** ONE call per save, carrying every dirty field as one op list (T5-01/A56). */
87
+ mutateOnce: (ops: readonly SettingsParamOp[]) => Promise<boolean>;
88
+ /** Ask the scope to drop one override; resolves when the scope answered, not when it landed. */
89
+ clear: (field: string) => Promise<boolean>;
90
+ /** The current row state, from whichever source owns it (the bound hook or the page). */
91
+ snapshot: ParamSectionSnapshot;
92
+ }
93
+ /**
94
+ * Render one row's card body from a supplied snapshot.
95
+ * @param props - the card data, its callbacks, and the row state to render.
96
+ * @returns the card.
97
+ */
98
+ export declare function ParamCardView(props: ParamCardViewProps): ReactNode;
99
+ /**
100
+ * The card as our own section renders it: the row state comes from the hook seat the
101
+ * renderer binds out of the inject face's `hooks` compartment (components never hold a
102
+ * subscription of their own).
103
+ * @param props - the card data, its callbacks, and the bound row hook.
104
+ * @returns the card.
105
+ */
106
+ export declare function ParamCard(props: ParamCardProps): ReactNode;
107
+ //# sourceMappingURL=ParamCard.d.ts.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The "writes awaiting approval" card: the staged write window, with the two decisions on each row.
3
+ *
4
+ * It is a card in the SAME section and wears the SAME shell as the parameter cards (header with title,
5
+ * count and chevron; body of field blocks; a button row per block), so nothing here invents a second
6
+ * visual language. Two things differ on purpose: the data comes from the host's approval routes rather
7
+ * than the settings transport, and its three states are distinct — "reading", "nothing staged" and "the
8
+ * read failed" each say so in their own words (E7: merging the first two is what made an empty panel
9
+ * look like lost data).
10
+ *
11
+ * Every decision re-reads the window instead of predicting the outcome: the host owns the state, and a
12
+ * refusal is shown with the host's own sentence.
13
+ * @module @lmzhen/dsh-evolution-ui/panels/settings/client/PendingCard
14
+ */
15
+ import { type ReactNode } from 'react';
16
+ import type { FallbackHint } from '@lmzhen/dsh-evolution-client-kit/generated/contracts';
17
+ import type { ApprovalApi } from './api.ts';
18
+ import type { MessageKey } from './messages.ts';
19
+ /** Injected face: the copy seat and the host calls. No hook compartment — this card keeps its own state. */
20
+ export interface PendingCardFace {
21
+ t: (key: MessageKey, values?: Readonly<Record<string, string | number>>) => string;
22
+ api: ApprovalApi;
23
+ /**
24
+ * U-6 (registry `approvalConfirm`): read PER RENDER, like the entry's own seat probe — a value
25
+ * captured once would pin the gate for the life of the fiber. Absent ⇒ the shipped default `auto`.
26
+ */
27
+ confirmMode?: () => 'auto' | 'ask' | 'timeout';
28
+ /** G5/W7 S4: the command-face fallback rendered with an unreachable/unauthenticated failure. */
29
+ fallback?: FallbackHint | undefined;
30
+ }
31
+ /**
32
+ * U-6: the registry's gate word, read out of a section's user layer. ONE definition, exported so the
33
+ * mapping itself is judgeable: the entry does the wiring, this does the reading. Anything that is not
34
+ * one of the two explicit words falls back to the shipped default (`auto`) — a document written by a
35
+ * future version must not silently turn the confirmation ON, and a typo must not turn it off. The
36
+ * independent review flagged that this reader had no case at all (P2-11).
37
+ */
38
+ export declare function confirmModeFrom(user: unknown): 'auto' | 'ask' | 'timeout';
39
+ /**
40
+ * Render the pending window.
41
+ * @param props - the copy seat and the host calls.
42
+ * @returns the card.
43
+ */
44
+ export declare function PendingCard(props: PendingCardFace): ReactNode;
45
+ //# sourceMappingURL=PendingCard.d.ts.map
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The Plugins page's per-row configuration entry for a family row.
3
+ *
4
+ * The page owns the settings subscription — it re-renders the entry — and passes the row's
5
+ * form in, so this component renders the SAME card body as our own section, fed by the
6
+ * page's state instead of the bound hook and therefore holding no subscription of its own.
7
+ * `summary` answers the page's one-line slot: a row's description fallback, which stays
8
+ * empty until the row actually overrides something, exactly as the page expects.
9
+ * @module @lmzhen/dsh-evolution-ui/panels/settings/client
10
+ */
11
+ import { type ReactNode } from 'react';
12
+ import type { ClientParamField } from './generated-params.ts';
13
+ import type { MessageKey } from './messages.ts';
14
+ import type { RowConfigViewProps } from './seam.ts';
15
+ /** The inject face every row registration carries (the page supplies `view` and `form`). */
16
+ export interface RowConfigFace {
17
+ /** The row's entry id, for the card title. */
18
+ namespace: string;
19
+ fields: readonly ClientParamField[];
20
+ t: (key: MessageKey, values?: Readonly<Record<string, string | number>>) => string;
21
+ }
22
+ /** Props one row entry is rendered with: the page's seat plus this row's own face. */
23
+ export type RowConfigCardProps = RowConfigViewProps & RowConfigFace;
24
+ /**
25
+ * Render one row's configuration entry.
26
+ * @param props - the page's view/form seat plus this row's face.
27
+ * @returns the entry; `summary` renders nothing for an untouched row (the page then keeps the row's own description).
28
+ */
29
+ export declare function RowConfigCard(props: RowConfigCardProps): ReactNode;
30
+ //# sourceMappingURL=RowConfigCard.d.ts.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The section shell: title, one-line explanation, then one card per namespace — with the staged-write
3
+ * window's card ahead of them all, because it is the only card here that waits on a decision.
4
+ *
5
+ * This is the shape the platform's own settings sections use — a heading plus the
6
+ * child slots it declared in its registration. The cards themselves are separate
7
+ * registrations keyed by namespace, so a namespace the Host does not serve simply
8
+ * renders nothing and a deployment that drops this row loses the whole section.
9
+ * @module @lmzhen/dsh-evolution-ui/panels/settings/client
10
+ */
11
+ import { type ReactNode } from 'react';
12
+ import { type SectionFace } from './seam.ts';
13
+ /**
14
+ * Render the section.
15
+ * @param face - the shell's inject face: translator and child-slot renderer.
16
+ * @returns the section element.
17
+ */
18
+ export declare function SettingsSection(face: SectionFace): ReactNode;
19
+ //# sourceMappingURL=SettingsSection.d.ts.map
@@ -0,0 +1,64 @@
1
+ import { type RouteAnswer } from '@lmzhen/dsh-evolution-client-kit/generated/route-client';
2
+ /** One staged write, as the pending route hands it over (never the staged args). */
3
+ export interface PendingRow {
4
+ readonly id: string;
5
+ readonly kind: 'memory' | 'skill' | 'capability';
6
+ readonly summary: string;
7
+ readonly createdAt: string;
8
+ /** How long ago it was staged, in the family's `{unit, n}` closed vocabulary. */
9
+ readonly age: {
10
+ readonly unit: string;
11
+ readonly n: number;
12
+ };
13
+ readonly status: 'pending' | 'executing' | 'approved' | 'rejected';
14
+ readonly claimedBy?: string | undefined;
15
+ }
16
+ /** One windowed hunk of a previewed change: the region the write would touch. */
17
+ export interface PreviewHunk {
18
+ readonly path: string;
19
+ readonly oldText: string;
20
+ readonly newText: string;
21
+ }
22
+ /**
23
+ * What a staged write WOULD store. `available: false` carries the host's reason — plenty of records have
24
+ * no bytes worth showing, and the reader is owed that sentence rather than an empty diff.
25
+ */
26
+ export type PreviewAnswer = {
27
+ readonly available: true;
28
+ readonly path: string;
29
+ readonly linesAdded: number;
30
+ readonly linesRemoved: number;
31
+ readonly hunks: readonly PreviewHunk[];
32
+ readonly truncated: boolean;
33
+ } | {
34
+ readonly available: false;
35
+ readonly reason: string;
36
+ };
37
+ /** What one call answered: the generated four-state RouteAnswer (no local failure vocabulary). */
38
+ export type ApprovalAnswer<T> = RouteAnswer<T>;
39
+ /**
40
+ * Which window the pending route is asked for. The host route has always taken `?status=` (the CLI
41
+ * asks for both); this half asked for neither, so a record stuck in `executing` — an approve that
42
+ * died between the claim and the decision, or another process running it — was invisible in the GUI
43
+ * while `/evolution pending` and doctor both listed it (T4-05/A47). `PendingRow.status` even declared
44
+ * the member, so the type face expected data the data face could not reach.
45
+ */
46
+ export type PendingWindow = 'pending' | 'executing';
47
+ /** How this bundle reaches the host. Injectable so a spec drives it without a server. */
48
+ export interface ApprovalApi {
49
+ /** The staged writes in one window; `pending` when the caller does not say. */
50
+ pending: (status?: PendingWindow) => Promise<ApprovalAnswer<readonly PendingRow[]>>;
51
+ /** Ask the host to replay one staged write. */
52
+ approve: (id: string) => Promise<ApprovalAnswer<unknown>>;
53
+ /** Close one staged write without replaying it. */
54
+ reject: (id: string) => Promise<ApprovalAnswer<unknown>>;
55
+ /** What that staged write would store, resolved by the host without running it. */
56
+ preview: (id: string) => Promise<ApprovalAnswer<PreviewAnswer>>;
57
+ }
58
+ /**
59
+ * Build the approval face over one fetch implementation.
60
+ * @param doFetch - the fetch to use (the platform's global in the browser, a fake in a spec).
61
+ * @returns the three calls the pending card makes.
62
+ */
63
+ export declare function createApprovalApi(doFetch: typeof fetch): ApprovalApi;
64
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1,28 @@
1
+ import { type RouteAnswer } from '@lmzhen/dsh-evolution-client-kit/generated/route-client';
2
+ import type { DiagnosticsView } from '@lmzhen/dsh-evolution-client-kit/generated/contracts';
3
+ /** What the card renders: the view, or the classified failure that kept it from arriving. */
4
+ export type DiagnosticsState = {
5
+ readonly phase: 'loading';
6
+ } | {
7
+ readonly phase: 'ready';
8
+ readonly view: DiagnosticsView;
9
+ } | {
10
+ readonly phase: 'failed';
11
+ readonly failure: import('@lmzhen/dsh-evolution-client-kit/generated/route-client').RouteFailure;
12
+ };
13
+ /** The one call the card makes. */
14
+ export interface DiagnosticsApi {
15
+ view(): Promise<RouteAnswer<DiagnosticsView>>;
16
+ }
17
+ /**
18
+ * Build the diagnostics face over one fetch implementation.
19
+ * @param doFetch - the browser fetch, or a spec stub.
20
+ */
21
+ export declare function createDiagnosticsApi(doFetch?: typeof fetch): DiagnosticsApi;
22
+ /**
23
+ * Read the view once and map it onto the card's four states (loading is the caller's initial value).
24
+ * @param doFetch - the fetch to use.
25
+ * @returns ready with the view, or failed with the classified failure.
26
+ */
27
+ export declare function loadDiagnostics(doFetch?: typeof fetch): Promise<DiagnosticsState>;
28
+ //# sourceMappingURL=diagnostics-state.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * GENERATED by packages/scripts/gen-about.mjs — do not edit.
3
+ *
4
+ * The version comes from the repository package.json and the purpose from this package own
5
+ * description, so the settings surface can state both without a hand-written copy.
6
+ */
7
+ /** The family version this surface belongs to. */
8
+ export declare const FAMILY_VERSION = "0.32.1";
9
+ /** What this surface is for, in one line. */
10
+ export declare const PACKAGE_PURPOSE = "Web UI umbrella for the evolution family: settings, merge, skill history and skill health panels";
11
+ //# sourceMappingURL=generated-about.d.ts.map