@qilin-agent/client-ui-settings-plugins 3.1.3 → 3.1.4

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.i18n.yaml CHANGED
@@ -5,48 +5,48 @@
5
5
  /:
6
6
  en: 1670ed782a12908d
7
7
  zh: 120007354cbbdb36
8
- /qilin-client-ui-settings-plugins:
9
- en: 1472d65a3e255835
10
- zh: 2db0ab0a4f7ef5ec
11
- /qilin-client-ui-settings-plugins/summary:
8
+ /qilin-agent-client-ui-settings-plugins:
9
+ en: 422cd671737b096e
10
+ zh: 9e9ef6a35b138742
11
+ /qilin-agent-client-ui-settings-plugins/summary:
12
12
  en: 7a676f7430c92e22
13
13
  zh: 2ff6a911f94d4de4
14
- /qilin-client-ui-settings-plugins/table-of-contents:
14
+ /qilin-agent-client-ui-settings-plugins/table-of-contents:
15
15
  en: d152484eb41ac6b4
16
16
  zh: 09388d293f9be9cb
17
- /qilin-client-ui-settings-plugins/use-this-package:
17
+ /qilin-agent-client-ui-settings-plugins/use-this-package:
18
18
  en: 2c3441975a279ff8
19
19
  zh: b0587417f7bc0141
20
- /qilin-client-ui-settings-plugins/use-this-package/what-appears-here:
20
+ /qilin-agent-client-ui-settings-plugins/use-this-package/what-appears-here:
21
21
  en: 3bd795b9a5b033dd
22
22
  zh: 95f3a6bac59864ba
23
- /qilin-client-ui-settings-plugins/use-this-package/editing-and-saving:
23
+ /qilin-agent-client-ui-settings-plugins/use-this-package/editing-and-saving:
24
24
  en: 3e8d3dbd9deb704a
25
25
  zh: 62f8ec8379ea4212
26
- /qilin-client-ui-settings-plugins/use-this-package/secret-role-fields:
26
+ /qilin-agent-client-ui-settings-plugins/use-this-package/secret-role-fields:
27
27
  en: aae49587945e1b84
28
28
  zh: 514b265ef099a9f1
29
- /qilin-client-ui-settings-plugins/understand-the-implementation:
29
+ /qilin-agent-client-ui-settings-plugins/understand-the-implementation:
30
30
  en: a7d99a0006373ba9
31
31
  zh: fd9560e1499fd274
32
- /qilin-client-ui-settings-plugins/understand-the-implementation/the-registration-rule:
32
+ /qilin-agent-client-ui-settings-plugins/understand-the-implementation/the-registration-rule:
33
33
  en: 13f4ba9841c81484
34
34
  zh: 870b18bd4c3c3b27
35
- /qilin-client-ui-settings-plugins/understand-the-implementation/the-write-path:
35
+ /qilin-agent-client-ui-settings-plugins/understand-the-implementation/the-write-path:
36
36
  en: 8e21487b8251d057
37
37
  zh: 9679617bac069cd3
38
- /qilin-client-ui-settings-plugins/further-exploration:
38
+ /qilin-agent-client-ui-settings-plugins/further-exploration:
39
39
  en: dd6103dffd4af94a
40
40
  zh: dd7e1dbffaf1aa5a
41
- /qilin-client-ui-settings-plugins/model-experience:
41
+ /qilin-agent-client-ui-settings-plugins/model-experience:
42
42
  en: 6b7c6f82ab6c8435
43
43
  zh: 3328550d96a6368b
44
- /qilin-client-ui-settings-plugins/model-experience/kv-cache-effect:
44
+ /qilin-agent-client-ui-settings-plugins/model-experience/kv-cache-effect:
45
45
  en: ca75c51c89c2c9b0
46
46
  zh: de54f3467ef3b9be
47
- /qilin-client-ui-settings-plugins/known-limitations-and-deferred-work:
47
+ /qilin-agent-client-ui-settings-plugins/known-limitations-and-deferred-work:
48
48
  en: fdadcbd489719e38
49
49
  zh: b7d8258224006047
50
- /qilin-client-ui-settings-plugins/known-limitations-and-deferred-work/dev-note:
50
+ /qilin-agent-client-ui-settings-plugins/known-limitations-and-deferred-work/dev-note:
51
51
  en: e67f633dc6fe7773
52
52
  zh: 3bb0c20c93f16f98
package/lib/client.js CHANGED
@@ -6,163 +6,9 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let _qilin_agent_client_ui_slots = require("@qilin-agent/client-ui-slots");
8
8
  let react_jsx_runtime = require("react/jsx-runtime");
9
- let react = require("react");
10
9
  let _qilin_agent_client_ui_primitives = require("@qilin-agent/client-ui-primitives");
10
+ let react = require("react");
11
11
  let _qilin_agent_client_store = require("@qilin-agent/client-store");
12
- //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-settings-plugins/src/client/fields.module.css.mjs
13
- const css$5 = ".qO6b8G_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.qO6b8G_field+.qO6b8G_field{border-top:.5px solid var(--qilin-alias-border-l2)}.qO6b8G_head{align-items:center;gap:8px;display:flex}.qO6b8G_label{min-width:0;color:var(--qilin-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.qO6b8G_labelGroup{flex:1;align-items:center;gap:4px;min-width:0;display:flex}.qO6b8G_labelGroup>.qO6b8G_label{flex:0 auto}.qO6b8G_helpButton{width:24px;height:24px;color:var(--qilin-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.qO6b8G_helpButton:hover,.qO6b8G_helpButton[aria-expanded=true]{background:var(--qilin-alias-bg-layer-4);color:var(--qilin-alias-label-secondary)}.qO6b8G_helpButton:focus-visible{outline:var(--qilin-focus-ring-width) solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:1px}.qO6b8G_help{color:var(--qilin-alias-label-secondary);padding:10px 0 0;font-size:12px;line-height:1.6}.qO6b8G_help>p{margin:0}.qO6b8G_help>p+p{margin-top:8px}.qO6b8G_badges{align-items:center;gap:8px;display:inline-flex}.qO6b8G_reset{font:inherit;color:var(--qilin-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.qO6b8G_reset:hover:not(:disabled){color:var(--qilin-alias-label-primary)}.qO6b8G_reset:disabled{cursor:default}.qO6b8G_input{border:.5px solid var(--qilin-alias-border-l4);background:var(--qilin-alias-bg-layer-3);height:34px;font:inherit;color:var(--qilin-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.qO6b8G_input:focus-visible{border-color:var(--qilin-alias-brand-primary);outline:none}.qO6b8G_input:disabled{color:var(--qilin-alias-label-tertiary);cursor:default}.qO6b8G_input[aria-invalid=true]{border-color:var(--qilin-alias-state-error-primary)}.qO6b8G_invalid{color:var(--qilin-alias-state-error-primary);margin:0;font-size:12px;line-height:1.5}.qO6b8G_hint{color:var(--qilin-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}";
14
- const tagId$5 = "@qilin-agent/client-ui-settings-plugins/fields.module.css";
15
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
16
- const tag = document.createElement("style");
17
- tag.dataset.plugin = "@qilin-agent/client-ui-settings-plugins";
18
- tag.dataset.pluginCss = tagId$5;
19
- tag.textContent = css$5;
20
- document.head.appendChild(tag);
21
- }
22
- var fields_module_css_default = {
23
- "badges": "qO6b8G_badges",
24
- "field": "qO6b8G_field",
25
- "head": "qO6b8G_head",
26
- "help": "qO6b8G_help",
27
- "helpButton": "qO6b8G_helpButton",
28
- "hint": "qO6b8G_hint",
29
- "input": "qO6b8G_input",
30
- "invalid": "qO6b8G_invalid",
31
- "label": "qO6b8G_label",
32
- "labelGroup": "qO6b8G_labelGroup",
33
- "reset": "qO6b8G_reset"
34
- };
35
- //#endregion
36
- //#region lib/types/client/fields.js
37
- /**
38
- * Hand-written controls for the plugin configuration forms. Each renders one
39
- * field's label, its staged text, whether saving would leave an override, and
40
- * — when one stands — the reset that stages a clear back to the composition
41
- * layer. Nothing here writes: a control reports what the user typed, and the
42
- * card's save is the single point where a draft becomes a document mutation.
43
- */
44
- /**
45
- * A staged value field. `numeric` only hints the keypad: which drafts a field
46
- * accepts is decided by its spec, so the control never silently rewrites what
47
- * the user typed.
48
- * @param props - the field's copy, its staged text, and the edit actions.
49
- * @returns the labelled control.
50
- */
51
- function ValueField(props) {
52
- const [helpOpen, setHelpOpen] = (0, react.useState)(false);
53
- const helpId = `${props.id}-help`;
54
- const messageId = `${props.id}-message`;
55
- const hasMessage = props.invalid || Boolean(props.hint);
56
- const description = [hasMessage ? messageId : "", helpOpen ? helpId : ""].filter(Boolean).join(" ");
57
- return (0, react_jsx_runtime.jsxs)("div", {
58
- className: fields_module_css_default.field,
59
- children: [
60
- (0, react_jsx_runtime.jsxs)("div", {
61
- className: fields_module_css_default.head,
62
- children: [(0, react_jsx_runtime.jsxs)("div", {
63
- className: fields_module_css_default.labelGroup,
64
- children: [(0, react_jsx_runtime.jsx)("label", {
65
- className: fields_module_css_default.label,
66
- htmlFor: props.id,
67
- children: props.label
68
- }), props.help !== void 0 ? (0, react_jsx_runtime.jsx)("button", {
69
- type: "button",
70
- className: fields_module_css_default.helpButton,
71
- "aria-label": props.help.label,
72
- "aria-expanded": helpOpen,
73
- "aria-controls": helpId,
74
- onClick: () => {
75
- setHelpOpen(!helpOpen);
76
- },
77
- children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconInfoOutline14, { size: 12 })
78
- }) : null]
79
- }), props.overridden ? (0, react_jsx_runtime.jsxs)("span", {
80
- className: fields_module_css_default.badges,
81
- children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Tag, {
82
- tone: "neutral",
83
- children: props.overriddenLabel
84
- }), (0, react_jsx_runtime.jsx)("button", {
85
- type: "button",
86
- className: fields_module_css_default.reset,
87
- disabled: props.disabled,
88
- onClick: props.onReset,
89
- children: props.resetLabel
90
- })]
91
- }) : null]
92
- }),
93
- (0, react_jsx_runtime.jsx)("input", {
94
- id: props.id,
95
- className: fields_module_css_default.input,
96
- type: "text",
97
- ...props.numeric === true ? { inputMode: "numeric" } : {},
98
- ...props.invalid ? { "aria-invalid": true } : {},
99
- "aria-describedby": description || void 0,
100
- value: props.text,
101
- placeholder: props.placeholder ?? "",
102
- disabled: props.disabled,
103
- onChange: (event) => {
104
- props.onEdit(event.target.value);
105
- }
106
- }),
107
- hasMessage ? (0, react_jsx_runtime.jsx)("p", {
108
- id: messageId,
109
- className: props.invalid ? fields_module_css_default.invalid : fields_module_css_default.hint,
110
- children: props.invalid ? props.invalidLabel : props.hint
111
- }) : null,
112
- props.help !== void 0 && helpOpen ? (0, react_jsx_runtime.jsx)("div", {
113
- id: helpId,
114
- className: fields_module_css_default.help,
115
- role: "region",
116
- "aria-label": props.help.label,
117
- children: props.help.content
118
- }) : null
119
- ]
120
- });
121
- }
122
- /**
123
- * A write-only credential control. The value never rides a response, so the
124
- * control reports only whether one is configured and starts blank; a blank
125
- * draft writes nothing, which keeps the stored key rather than clearing it.
126
- * @param props - the field's copy, its staged text, and the configured state.
127
- * @returns the labelled control.
128
- */
129
- function SecretField(props) {
130
- return (0, react_jsx_runtime.jsxs)("div", {
131
- className: fields_module_css_default.field,
132
- children: [
133
- (0, react_jsx_runtime.jsxs)("div", {
134
- className: fields_module_css_default.head,
135
- children: [(0, react_jsx_runtime.jsx)("label", {
136
- className: fields_module_css_default.label,
137
- htmlFor: props.id,
138
- children: props.label
139
- }), (0, react_jsx_runtime.jsx)("span", {
140
- className: fields_module_css_default.badges,
141
- children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Tag, {
142
- tone: props.configured ? "neutral" : "quiet",
143
- children: props.stateLabel
144
- })
145
- })]
146
- }),
147
- (0, react_jsx_runtime.jsx)("input", {
148
- id: props.id,
149
- className: fields_module_css_default.input,
150
- type: "password",
151
- autoComplete: "off",
152
- value: props.text,
153
- disabled: props.disabled,
154
- onChange: (event) => {
155
- props.onEdit(event.target.value);
156
- }
157
- }),
158
- (0, react_jsx_runtime.jsx)("p", {
159
- className: fields_module_css_default.hint,
160
- children: props.hint
161
- })
162
- ]
163
- });
164
- }
165
- //#endregion
166
12
  //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-settings-plugins/src/client/PluginConfigForm.module.css.mjs
167
13
  const css$4 = ".PuF0xa_form{flex-direction:column;display:flex}.PuF0xa_readOnly,.PuF0xa_unavailable{color:var(--qilin-alias-label-tertiary);margin:0 0 12px;font-size:12px;line-height:1.5}.PuF0xa_footer{align-items:center;gap:8px;padding-top:16px;display:flex}.PuF0xa_failed{min-width:0;color:var(--qilin-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.PuF0xa_save{appearance:none;font:inherit;cursor:pointer;background:var(--qilin-alias-label-primary);color:var(--qilin-alias-bg-layer-3);border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.PuF0xa_save:disabled{opacity:.4;cursor:default}.PuF0xa_save:focus-visible{outline:var(--qilin-focus-ring-width) solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:1px}";
168
14
  const tagId$4 = "@qilin-agent/client-ui-settings-plugins/PluginConfigForm.module.css";
@@ -254,7 +100,7 @@ window.__ModuleLoader__.load({
254
100
  state,
255
101
  onSave: props.save,
256
102
  onDiscard: props.discard,
257
- children: (0, react_jsx_runtime.jsx)(ValueField, {
103
+ children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
258
104
  id: "plugin-config-agent-loop-parallel",
259
105
  label: t("agentLoopMaxParallel"),
260
106
  hint: t("agentLoopMaxParallelHint"),
@@ -290,7 +136,7 @@ window.__ModuleLoader__.load({
290
136
  state,
291
137
  onSave: props.save,
292
138
  onDiscard: props.discard,
293
- children: [(0, react_jsx_runtime.jsx)(ValueField, {
139
+ children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
294
140
  id: "plugin-config-bash-timeout",
295
141
  label: t("bashTimeoutMs"),
296
142
  hint: t("bashTimeoutMsHint"),
@@ -306,7 +152,7 @@ window.__ModuleLoader__.load({
306
152
  onReset: () => {
307
153
  props.resetField("timeoutMs");
308
154
  }
309
- }), (0, react_jsx_runtime.jsx)(ValueField, {
155
+ }), (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
310
156
  id: "plugin-config-bash-output",
311
157
  label: t("bashMaxOutputBytes"),
312
158
  hint: t("bashMaxOutputBytesHint"),
@@ -475,7 +321,7 @@ window.__ModuleLoader__.load({
475
321
  className: SubagentLimitsFields_module_css_default.limits,
476
322
  children: [(0, react_jsx_runtime.jsx)("div", {
477
323
  className: SubagentLimitsFields_module_css_default.limit,
478
- children: (0, react_jsx_runtime.jsx)(ValueField, {
324
+ children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
479
325
  id: "plugin-config-subagent-depth",
480
326
  label: t("subagentMaxDepth"),
481
327
  help: {
@@ -511,7 +357,7 @@ window.__ModuleLoader__.load({
511
357
  })
512
358
  }), (0, react_jsx_runtime.jsx)("div", {
513
359
  className: SubagentLimitsFields_module_css_default.limit,
514
- children: (0, react_jsx_runtime.jsx)(ValueField, {
360
+ children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
515
361
  id: "plugin-config-subagent-capacity",
516
362
  label: t("subagentMaxActive"),
517
363
  help: {
@@ -812,280 +658,10 @@ window.__ModuleLoader__.load({
812
658
  });
813
659
  }
814
660
  //#endregion
815
- //#region lib/types/client/card-form.js
816
- /**
817
- * Shared form model behind every plugin card.
818
- *
819
- * A card stages what the user types and writes it only when they save. Each
820
- * settings write is a durable, revision-fenced document mutation, so a control
821
- * that committed as it settled turned one edit into a write the user never
822
- * asked for and could not preview; staged text makes what is on screen exactly
823
- * what a save would store.
824
- *
825
- * A field shows its effective value — the user layer over the composition
826
- * layer over the schema default — and whether the user layer carries it. That
827
- * presence, not a value comparison, is what marks a field overridden: an
828
- * override equal to the composition default is still an override.
829
- */
830
- /**
831
- * A whole-number field. An empty draft clears the field; any other draft that
832
- * is not a finite number blocks the save.
833
- * @param field - field name inside the namespace section.
834
- * @returns the field's conversion spec.
835
- */
836
- function numberField(field) {
837
- return {
838
- field,
839
- format: (value) => typeof value === "number" ? String(value) : "",
840
- parse: (text) => {
841
- const trimmed = text.trim();
842
- if (trimmed === "") return { kind: "clear" };
843
- const parsed = Number(trimmed);
844
- return Number.isFinite(parsed) ? {
845
- kind: "set",
846
- value: parsed
847
- } : void 0;
848
- }
849
- };
850
- }
851
- /**
852
- * A free-text field. An empty draft clears the field, so emptying the control
853
- * and saving is the same gesture as resetting it.
854
- * @param field - field name inside the namespace section.
855
- * @returns the field's conversion spec.
856
- */
857
- function textField(field) {
858
- return {
859
- field,
860
- format: (value) => typeof value === "string" ? value : "",
861
- parse: (text) => {
862
- const trimmed = text.trim();
863
- return trimmed === "" ? { kind: "clear" } : {
864
- kind: "set",
865
- value: trimmed
866
- };
867
- }
868
- };
869
- }
870
- /**
871
- * Stages one card's edits over one settings namespace and writes them on save.
872
- *
873
- * The form publishes through a snapshot store because slot components read
874
- * through a snapshot selector, while both the scope and the local drafts
875
- * change underneath; every projection is rebuilt from the two together.
876
- */
877
- var CardForm = class {
878
- scope;
879
- specs;
880
- secretSpecs;
881
- staged = /* @__PURE__ */ new Map();
882
- listeners = /* @__PURE__ */ new Set();
883
- saving = false;
884
- failed = false;
885
- /**
886
- * @param scope - the bound settings scope for this card's namespace.
887
- * @param specs - the section fields this card edits.
888
- * @param secrets - the card's write-only controls, written outside the section.
889
- */
890
- constructor(scope, specs, secrets = []) {
891
- this.scope = scope;
892
- this.specs = new Map(specs.map((spec) => [spec.field, spec]));
893
- this.secretSpecs = new Map(secrets.map((spec) => [spec.field, spec]));
894
- scope.subscribe(() => {
895
- this.publish();
896
- });
897
- }
898
- /**
899
- * Publish a projection of this form, rebuilt whenever the scope or a draft changes.
900
- * @param project - build the card's state from the form's current reads.
901
- * @returns the store the card's component reads through its bound selector.
902
- */
903
- bind(project) {
904
- const store = (0, _qilin_agent_client_store.createSnapshotStore)(project());
905
- this.listeners.add(() => {
906
- store.set(project());
907
- });
908
- return store;
909
- }
910
- /**
911
- * Read the card-level state: what the Host serves, and what a save would do.
912
- * @returns the form state every card shares.
913
- */
914
- shell() {
915
- const snapshot = this.scope.getSnapshot();
916
- const plan = this.plan();
917
- return {
918
- available: snapshot.status === "ready",
919
- writable: snapshot.writable,
920
- dirty: plan.length > 0,
921
- invalid: plan.some((item) => item.run === void 0),
922
- saving: this.saving,
923
- failed: this.failed
924
- };
925
- }
926
- /**
927
- * Read one control's state.
928
- * @param field - field name of a section field or of a write-only control.
929
- * @returns the draft text, whether a save would leave an override, and whether it is invalid.
930
- */
931
- field(field) {
932
- const staged = this.staged.get(field);
933
- if (this.secretSpecs.has(field)) return {
934
- text: staged?.text ?? "",
935
- overridden: false,
936
- invalid: false
937
- };
938
- const spec = this.spec(field);
939
- if (staged === void 0) return {
940
- text: spec.format(this.sectionValue(field)),
941
- overridden: this.stored(field),
942
- invalid: false
943
- };
944
- const write = staged.clear ? { kind: "clear" } : spec.parse(staged.text);
945
- return {
946
- text: staged.text,
947
- overridden: write?.kind === "set",
948
- invalid: write === void 0
949
- };
950
- }
951
- /**
952
- * Build the edit, reset, save, and discard actions bound to this form.
953
- * @returns the actions a card's slot entry injects.
954
- */
955
- actions() {
956
- return {
957
- edit: (field, text) => {
958
- this.stage(field, {
959
- text,
960
- clear: false
961
- });
962
- },
963
- resetField: (field) => {
964
- this.stage(field, {
965
- text: this.spec(field).format(this.baseValue(field)),
966
- clear: true
967
- });
968
- },
969
- save: () => {
970
- this.save();
971
- },
972
- discard: () => {
973
- if (this.staged.size === 0 && !this.failed) return;
974
- this.staged.clear();
975
- this.failed = false;
976
- this.publish();
977
- }
978
- };
979
- }
980
- /**
981
- * Write every staged edit, then re-seed from what the Host accepted.
982
- *
983
- * The Host is the only authority on whether a value was accepted — its
984
- * validators own the constraints no schema can express — so the outcome is
985
- * read back from the section rather than predicted here. A save that did not
986
- * land keeps its drafts, so the user can correct them instead of retyping.
987
- * @returns settlement after every write and the read-back.
988
- */
989
- async save() {
990
- const plan = this.plan();
991
- const writes = plan.flatMap((item) => item.run === void 0 ? [] : [item.run]);
992
- if (plan.length === 0 || this.saving || writes.length !== plan.length) return;
993
- this.saving = true;
994
- this.failed = false;
995
- this.publish();
996
- let landed = true;
997
- for (const write of writes) landed = await write() && landed;
998
- if (landed) this.staged.clear();
999
- this.saving = false;
1000
- this.failed = !landed;
1001
- this.publish();
1002
- }
1003
- /**
1004
- * Every staged edit a save would write. An entry whose draft is not a value
1005
- * its field accepts carries no write: the form is still dirty, and the save
1006
- * refuses rather than dropping the edit.
1007
- * @returns the planned writes, in the order the fields were staged.
1008
- */
1009
- plan() {
1010
- const plan = [];
1011
- for (const [field, staged] of this.staged) {
1012
- const secret = this.secretSpecs.get(field);
1013
- if (secret !== void 0) {
1014
- const value = staged.text.trim();
1015
- if (value !== "") plan.push({
1016
- field,
1017
- run: () => secret.write(value)
1018
- });
1019
- continue;
1020
- }
1021
- const spec = this.spec(field);
1022
- if (staged.clear) {
1023
- if (this.stored(field)) plan.push({
1024
- field,
1025
- run: () => this.clear(field)
1026
- });
1027
- continue;
1028
- }
1029
- if (staged.text === spec.format(this.sectionValue(field))) continue;
1030
- const write = spec.parse(staged.text);
1031
- if (write === void 0) plan.push({
1032
- field,
1033
- run: void 0
1034
- });
1035
- else if (write.kind === "clear") plan.push({
1036
- field,
1037
- run: () => this.clear(field)
1038
- });
1039
- else plan.push({
1040
- field,
1041
- run: () => this.store(field, write.value)
1042
- });
1043
- }
1044
- return plan;
1045
- }
1046
- async clear(field) {
1047
- await this.scope.unset(field);
1048
- return !this.stored(field);
1049
- }
1050
- async store(field, value) {
1051
- await this.scope.set(field, value);
1052
- return this.userLayer()?.[field] === value;
1053
- }
1054
- stage(field, edit) {
1055
- this.staged.set(field, edit);
1056
- this.failed = false;
1057
- this.publish();
1058
- }
1059
- spec(field) {
1060
- const spec = this.specs.get(field);
1061
- if (spec === void 0) throw new Error(`plugin card has no field ${field}`);
1062
- return spec;
1063
- }
1064
- snapshotOf() {
1065
- return this.scope.getSnapshot();
1066
- }
1067
- sectionValue(field) {
1068
- return this.snapshotOf().value?.[field];
1069
- }
1070
- baseValue(field) {
1071
- return this.snapshotOf().base?.[field];
1072
- }
1073
- userLayer() {
1074
- return this.snapshotOf().user;
1075
- }
1076
- stored(field) {
1077
- const user = this.userLayer();
1078
- return user !== void 0 && Object.hasOwn(user, field);
1079
- }
1080
- publish() {
1081
- for (const listener of this.listeners) listener();
1082
- }
1083
- };
1084
- //#endregion
1085
661
  //#region lib/types/client/subagent-limits-card-controller.js
1086
662
  /** Staged delegation limits backed by the Host's subagent settings section. */
1087
663
  function limitField(field, minimum) {
1088
- const numeric = numberField(field);
664
+ const numeric = (0, _qilin_agent_client_ui_primitives.settingsNumberField)(field);
1089
665
  return {
1090
666
  ...numeric,
1091
667
  parse: (text) => {
@@ -1102,7 +678,7 @@ window.__ModuleLoader__.load({
1102
678
  store;
1103
679
  /** @param scope - The Host's `subagent` settings section. */
1104
680
  constructor(scope) {
1105
- this.form = new CardForm(scope, [limitField("maxDepth", 0), limitField("maxActiveSubagents", 1)]);
681
+ this.form = new _qilin_agent_client_ui_primitives.SettingsFormModel(scope, [limitField("maxDepth", 0), limitField("maxActiveSubagents", 1)]);
1106
682
  this.store = this.form.bind(() => ({
1107
683
  ...this.form.shell(),
1108
684
  maxDepth: this.form.field("maxDepth"),
@@ -1144,7 +720,7 @@ window.__ModuleLoader__.load({
1144
720
  onSave: props.save,
1145
721
  onDiscard: props.discard,
1146
722
  children: [
1147
- (0, react_jsx_runtime.jsx)(ValueField, {
723
+ (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
1148
724
  id: "plugin-config-git-bin",
1149
725
  label: t("gitBin"),
1150
726
  hint: t("gitBinHint"),
@@ -1157,7 +733,7 @@ window.__ModuleLoader__.load({
1157
733
  props.resetField("gitBin");
1158
734
  }
1159
735
  }),
1160
- (0, react_jsx_runtime.jsx)(ValueField, {
736
+ (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
1161
737
  id: "plugin-config-gh-bin",
1162
738
  label: t("ghBin"),
1163
739
  hint: t("ghBinHint"),
@@ -1170,7 +746,7 @@ window.__ModuleLoader__.load({
1170
746
  props.resetField("ghBin");
1171
747
  }
1172
748
  }),
1173
- (0, react_jsx_runtime.jsx)(ValueField, {
749
+ (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
1174
750
  id: "plugin-config-git-timeout",
1175
751
  label: t("gitTimeoutMs"),
1176
752
  hint: t("gitTimeoutMsHint"),
@@ -1184,7 +760,7 @@ window.__ModuleLoader__.load({
1184
760
  props.resetField("timeoutMs");
1185
761
  }
1186
762
  }),
1187
- (0, react_jsx_runtime.jsx)(ValueField, {
763
+ (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
1188
764
  id: "plugin-config-git-discovery-timeout",
1189
765
  label: t("gitDiscoveryTimeoutMs"),
1190
766
  hint: t("gitDiscoveryTimeoutMsHint"),
@@ -1198,7 +774,7 @@ window.__ModuleLoader__.load({
1198
774
  props.resetField("discoveryTimeoutMs");
1199
775
  }
1200
776
  }),
1201
- (0, react_jsx_runtime.jsx)(ValueField, {
777
+ (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
1202
778
  id: "plugin-config-gh-timeout",
1203
779
  label: t("ghTimeoutMs"),
1204
780
  hint: t("ghTimeoutMsHint"),
@@ -1212,7 +788,7 @@ window.__ModuleLoader__.load({
1212
788
  props.resetField("ghTimeoutMs");
1213
789
  }
1214
790
  }),
1215
- (0, react_jsx_runtime.jsx)(ValueField, {
791
+ (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
1216
792
  id: "plugin-config-git-max-diff",
1217
793
  label: t("gitMaxDiffBytes"),
1218
794
  hint: t("gitMaxDiffBytesHint"),
@@ -1226,7 +802,7 @@ window.__ModuleLoader__.load({
1226
802
  props.resetField("maxDiffBytes");
1227
803
  }
1228
804
  }),
1229
- (0, react_jsx_runtime.jsx)(ValueField, {
805
+ (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
1230
806
  id: "plugin-config-git-max-stderr",
1231
807
  label: t("gitMaxStderrChars"),
1232
808
  hint: t("gitMaxStderrCharsHint"),
@@ -1240,7 +816,7 @@ window.__ModuleLoader__.load({
1240
816
  props.resetField("maxStderrChars");
1241
817
  }
1242
818
  }),
1243
- (0, react_jsx_runtime.jsx)(ValueField, {
819
+ (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
1244
820
  id: "plugin-config-git-max-list",
1245
821
  label: t("gitMaxListEntries"),
1246
822
  hint: t("gitMaxListEntriesHint"),
@@ -1275,7 +851,7 @@ window.__ModuleLoader__.load({
1275
851
  onSave: props.save,
1276
852
  onDiscard: props.discard,
1277
853
  children: [
1278
- (0, react_jsx_runtime.jsx)(SecretField, {
854
+ (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsSecretField, {
1279
855
  id: "plugin-config-web-search-key",
1280
856
  label: t("webSearchApiKey"),
1281
857
  hint: t("webSearchApiKeyHint"),
@@ -1287,7 +863,7 @@ window.__ModuleLoader__.load({
1287
863
  props.edit("apiKey", text);
1288
864
  }
1289
865
  }),
1290
- (0, react_jsx_runtime.jsx)(ValueField, {
866
+ (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
1291
867
  id: "plugin-config-web-search-endpoint",
1292
868
  label: t("webSearchBaseUrl"),
1293
869
  hint: t("webSearchBaseUrlHint"),
@@ -1303,7 +879,7 @@ window.__ModuleLoader__.load({
1303
879
  props.resetField("baseURL");
1304
880
  }
1305
881
  }),
1306
- (0, react_jsx_runtime.jsx)(ValueField, {
882
+ (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
1307
883
  id: "plugin-config-web-search-max-uses",
1308
884
  label: t("webSearchMaxUses"),
1309
885
  hint: t("webSearchMaxUsesHint"),
@@ -1337,7 +913,7 @@ window.__ModuleLoader__.load({
1337
913
  store;
1338
914
  /** @param scope - the bound settings scope for the `agent-loop` namespace. */
1339
915
  constructor(scope) {
1340
- this.form = new CardForm(scope, [numberField("maxParallelToolCalls")]);
916
+ this.form = new _qilin_agent_client_ui_primitives.SettingsFormModel(scope, [(0, _qilin_agent_client_ui_primitives.settingsNumberField)("maxParallelToolCalls")]);
1341
917
  this.store = this.form.bind(() => this.projection());
1342
918
  }
1343
919
  projection() {
@@ -1372,7 +948,7 @@ window.__ModuleLoader__.load({
1372
948
  store;
1373
949
  /** @param scope - the bound settings scope for the `bash` namespace. */
1374
950
  constructor(scope) {
1375
- this.form = new CardForm(scope, [numberField("timeoutMs"), numberField("maxOutputBytes")]);
951
+ this.form = new _qilin_agent_client_ui_primitives.SettingsFormModel(scope, [(0, _qilin_agent_client_ui_primitives.settingsNumberField)("timeoutMs"), (0, _qilin_agent_client_ui_primitives.settingsNumberField)("maxOutputBytes")]);
1376
952
  this.store = this.form.bind(() => this.projection());
1377
953
  }
1378
954
  projection() {
@@ -1408,15 +984,15 @@ window.__ModuleLoader__.load({
1408
984
  store;
1409
985
  /** @param scope - the bound settings scope for the `workspace-git` namespace. */
1410
986
  constructor(scope) {
1411
- this.form = new CardForm(scope, [
1412
- textField("gitBin"),
1413
- textField("ghBin"),
1414
- numberField("timeoutMs"),
1415
- numberField("discoveryTimeoutMs"),
1416
- numberField("ghTimeoutMs"),
1417
- numberField("maxDiffBytes"),
1418
- numberField("maxStderrChars"),
1419
- numberField("maxListEntries")
987
+ this.form = new _qilin_agent_client_ui_primitives.SettingsFormModel(scope, [
988
+ (0, _qilin_agent_client_ui_primitives.settingsTextField)("gitBin"),
989
+ (0, _qilin_agent_client_ui_primitives.settingsTextField)("ghBin"),
990
+ (0, _qilin_agent_client_ui_primitives.settingsNumberField)("timeoutMs"),
991
+ (0, _qilin_agent_client_ui_primitives.settingsNumberField)("discoveryTimeoutMs"),
992
+ (0, _qilin_agent_client_ui_primitives.settingsNumberField)("ghTimeoutMs"),
993
+ (0, _qilin_agent_client_ui_primitives.settingsNumberField)("maxDiffBytes"),
994
+ (0, _qilin_agent_client_ui_primitives.settingsNumberField)("maxStderrChars"),
995
+ (0, _qilin_agent_client_ui_primitives.settingsNumberField)("maxListEntries")
1420
996
  ]);
1421
997
  this.store = this.form.bind(() => this.projection());
1422
998
  }
@@ -1759,7 +1335,7 @@ window.__ModuleLoader__.load({
1759
1335
  constructor(scope, ctx) {
1760
1336
  this.scope = scope;
1761
1337
  this.ctx = ctx;
1762
- this.form = new CardForm(scope, [textField("baseURL"), numberField("maxUses")], [{
1338
+ this.form = new _qilin_agent_client_ui_primitives.SettingsFormModel(scope, [(0, _qilin_agent_client_ui_primitives.settingsTextField)("baseURL"), (0, _qilin_agent_client_ui_primitives.settingsNumberField)("maxUses")], [{
1763
1339
  field: API_KEY_FIELD,
1764
1340
  write: (text) => this.writeKey(text)
1765
1341
  }]);
@@ -10,14 +10,14 @@
10
10
  * showing fields nothing would accept.
11
11
  */
12
12
  import { type ReactNode } from 'react';
13
- import type { CardShell } from './card-form.ts';
13
+ import type { SettingsFormShell } from '@qilin-agent/client-ui-primitives';
14
14
  import type { PluginsSettingsLocaleKey } from './locales.ts';
15
15
  /** Form chrome shared by every plugin configuration page. */
16
16
  export interface PluginConfigFormProps {
17
17
  /** Locale reader for this package's copy. */
18
18
  t: (key: PluginsSettingsLocaleKey) => string;
19
19
  /** The form state: availability, writability, and what a save would do. */
20
- state: CardShell;
20
+ state: SettingsFormShell;
21
21
  /** Write every staged edit. */
22
22
  onSave: () => void;
23
23
  /** Drop every staged edit; the form calls it when it leaves the page. */
@@ -1,7 +1,7 @@
1
1
  /** The agent-loop card's staged form over the `agent-loop` settings namespace. */
2
2
  import type { SnapshotStore } from '@qilin-agent/client-store';
3
3
  import type { ConfigForm } from '@qilin-agent/client-ui-settings/client';
4
- import { type CardActions, type CardFieldState, type CardShell } from './card-form.ts';
4
+ import { type SettingsFormActions, type SettingsFieldState, type SettingsFormShell } from '@qilin-agent/client-ui-primitives';
5
5
  /**
6
6
  * Namespace of the agent loop's user-owned settings. Spelled here rather than
7
7
  * imported: a client package must not depend on a Host package.
@@ -16,12 +16,12 @@ export interface AgentLoopSettings {
16
16
  maxParallelToolCalls?: number;
17
17
  }
18
18
  /** What the agent-loop card renders. */
19
- export interface AgentLoopCardState extends CardShell {
19
+ export interface AgentLoopCardState extends SettingsFormShell {
20
20
  /** Parallel tool-call cap. */
21
- maxParallelToolCalls: CardFieldState;
21
+ maxParallelToolCalls: SettingsFieldState;
22
22
  }
23
23
  /** The registration-side face the agent-loop card's slot entry injects. */
24
- export interface AgentLoopCardFace extends CardActions {
24
+ export interface AgentLoopCardFace extends SettingsFormActions {
25
25
  hooks: {
26
26
  /** Card snapshot bound by the renderer as useAgentLoopCard. */
27
27
  agentLoopCard: SnapshotStore<AgentLoopCardState>;
@@ -1,7 +1,7 @@
1
1
  /** The shell card's staged form over the `bash` settings namespace. */
2
2
  import type { SnapshotStore } from '@qilin-agent/client-store';
3
3
  import type { ConfigForm } from '@qilin-agent/client-ui-settings/client';
4
- import { type CardActions, type CardFieldState, type CardShell } from './card-form.ts';
4
+ import { type SettingsFormActions, type SettingsFieldState, type SettingsFormShell } from '@qilin-agent/client-ui-primitives';
5
5
  /**
6
6
  * Namespace of the shell capability. Spelled here rather than imported: a
7
7
  * client package must not depend on a Host package, and the executor families
@@ -16,14 +16,14 @@ export interface BashSettings {
16
16
  maxOutputBytes?: number;
17
17
  }
18
18
  /** What the shell card renders. */
19
- export interface BashCardState extends CardShell {
19
+ export interface BashCardState extends SettingsFormShell {
20
20
  /** Command timeout in milliseconds. */
21
- timeoutMs: CardFieldState;
21
+ timeoutMs: SettingsFieldState;
22
22
  /** Per-stream output cap in bytes. */
23
- maxOutputBytes: CardFieldState;
23
+ maxOutputBytes: SettingsFieldState;
24
24
  }
25
25
  /** The registration-side face the shell card's slot entry injects. */
26
- export interface BashCardFace extends CardActions {
26
+ export interface BashCardFace extends SettingsFormActions {
27
27
  hooks: {
28
28
  /** Card snapshot bound by the renderer as useBashCard. */
29
29
  bashCard: SnapshotStore<BashCardState>;
@@ -1,7 +1,7 @@
1
1
  /** The Git card's staged form over the `workspace-git` settings namespace. */
2
2
  import type { SnapshotStore } from '@qilin-agent/client-store';
3
3
  import type { ConfigForm } from '@qilin-agent/client-ui-settings/client';
4
- import { type CardActions, type CardFieldState, type CardShell } from './card-form.ts';
4
+ import { type SettingsFormActions, type SettingsFieldState, type SettingsFormShell } from '@qilin-agent/client-ui-primitives';
5
5
  /**
6
6
  * Namespace of the workspace Git service. Spelled here rather than imported:
7
7
  * a client package must not depend on a Host package, and the service plugin
@@ -28,26 +28,26 @@ export interface GitSettings {
28
28
  maxListEntries?: number;
29
29
  }
30
30
  /** What the Git card renders. */
31
- export interface GitCardState extends CardShell {
31
+ export interface GitCardState extends SettingsFormShell {
32
32
  /** Git executable path. */
33
- gitBin: CardFieldState;
33
+ gitBin: SettingsFieldState;
34
34
  /** gh executable path. */
35
- ghBin: CardFieldState;
35
+ ghBin: SettingsFieldState;
36
36
  /** Content or mutation command timeout. */
37
- timeoutMs: CardFieldState;
37
+ timeoutMs: SettingsFieldState;
38
38
  /** Repository-discovery command timeout. */
39
- discoveryTimeoutMs: CardFieldState;
39
+ discoveryTimeoutMs: SettingsFieldState;
40
40
  /** gh command timeout. */
41
- ghTimeoutMs: CardFieldState;
41
+ ghTimeoutMs: SettingsFieldState;
42
42
  /** Diff answer cap. */
43
- maxDiffBytes: CardFieldState;
43
+ maxDiffBytes: SettingsFieldState;
44
44
  /** stderr answer cap. */
45
- maxStderrChars: CardFieldState;
45
+ maxStderrChars: SettingsFieldState;
46
46
  /** List entry cap. */
47
- maxListEntries: CardFieldState;
47
+ maxListEntries: SettingsFieldState;
48
48
  }
49
49
  /** The registration-side face the Git card's slot entry injects. */
50
- export interface GitCardFace extends CardActions {
50
+ export interface GitCardFace extends SettingsFormActions {
51
51
  hooks: {
52
52
  /** Card snapshot bound by the renderer as useGitCard. */
53
53
  gitCard: SnapshotStore<GitCardState>;
@@ -11,8 +11,8 @@
11
11
  import type { Context as ClientContext } from '@qilin-agent/kylin';
12
12
  export type { PluginsSettingsSectionInjected, PluginsSettingsSectionProps } from './PluginsSettingsSection.tsx';
13
13
  export type { PluginConfigFormProps } from './PluginConfigForm.tsx';
14
- export type { FieldProps } from './fields.tsx';
15
- export type { CardActions, CardFieldSpec, CardFieldState, CardSecretSpec, CardShell, } from './card-form.ts';
14
+ export type { SettingsFieldProps } from '@qilin-agent/client-ui-primitives';
15
+ export type { SettingsFormActions, SettingsFieldSpec, SettingsFieldState, SettingsSecretSpec, SettingsFormShell, } from '@qilin-agent/client-ui-primitives';
16
16
  export type { AgentLoopCardFace, AgentLoopCardState } from './agent-loop-card-controller.ts';
17
17
  export type { BashCardFace, BashCardState } from './bash-card-controller.ts';
18
18
  export type { WebSearchCardFace, WebSearchCardState } from './web-search-card-controller.ts';
@@ -1,5 +1,5 @@
1
1
  /** Shared presentation and actions for the two Host-owned Subagent settings sections. */
2
- import type { CardShell } from './card-form.ts';
2
+ import type { SettingsFormShell } from '@qilin-agent/client-ui-primitives';
3
3
  import type { SubagentLimitsCardFace, SubagentLimitsCardState } from './subagent-limits-card-controller.ts';
4
4
  import type { SubagentModelSelectionCardFace, SubagentModelSelectionCardState } from './subagent-model-selection-card-controller.ts';
5
5
  /** Both existing form sources and the actions exposed by one Subagent card. */
@@ -21,7 +21,7 @@ export interface SubagentCardFace {
21
21
  * @param models - Current model-authorization form.
22
22
  * @returns Availability and settlement across the sections this Host serves.
23
23
  */
24
- export declare function subagentCardShell(limits: SubagentLimitsCardState, models: SubagentModelSelectionCardState): CardShell;
24
+ export declare function subagentCardShell(limits: SubagentLimitsCardState, models: SubagentModelSelectionCardState): SettingsFormShell;
25
25
  /**
26
26
  * Compose one card from the existing forms; each write retains its namespace revision fence.
27
27
  * @param limits - Limit form source and actions.
@@ -1,19 +1,19 @@
1
1
  /** Staged delegation limits backed by the Host's subagent settings section. */
2
2
  import type { SnapshotStore } from '@qilin-agent/client-store';
3
3
  import type { ConfigForm } from '@qilin-agent/client-ui-settings/client';
4
- import { type CardActions, type CardFieldState, type CardShell } from './card-form.ts';
4
+ import { type SettingsFormActions, type SettingsFieldState, type SettingsFormShell } from '@qilin-agent/client-ui-primitives';
5
5
  /** Host-owned delegation defaults and live capacity. */
6
6
  export interface SubagentLimitsSettings {
7
7
  maxDepth: number;
8
8
  maxActiveSubagents: number;
9
9
  }
10
10
  /** Effective values and drafts presented by the limits card. */
11
- export interface SubagentLimitsCardState extends CardShell {
12
- maxDepth: CardFieldState;
13
- maxActiveSubagents: CardFieldState;
11
+ export interface SubagentLimitsCardState extends SettingsFormShell {
12
+ maxDepth: SettingsFieldState;
13
+ maxActiveSubagents: SettingsFieldState;
14
14
  }
15
15
  /** Actions and observable state bound by the slot renderer. */
16
- export interface SubagentLimitsCardFace extends CardActions {
16
+ export interface SubagentLimitsCardFace extends SettingsFormActions {
17
17
  hooks: {
18
18
  subagentLimitsCard: SnapshotStore<SubagentLimitsCardState>;
19
19
  };
@@ -3,7 +3,7 @@ import type { Context as ClientContext } from '@qilin-agent/kylin';
3
3
  import type { ModelProviderGroup } from '@qilin-agent/api-remotes/client';
4
4
  import { type SnapshotStore } from '@qilin-agent/client-store';
5
5
  import type { ConfigForm } from '@qilin-agent/client-ui-settings/client';
6
- import type { CardShell } from './card-form.ts';
6
+ import type { SettingsFormShell } from '@qilin-agent/client-ui-primitives';
7
7
  /** Namespace of the Host-owned subagent model-selection preference. */
8
8
  export declare const SUBAGENT_MODEL_SELECTION_NS = "subagent-model-selection";
9
9
  /** One exact provider/model route stored as user authorization. */
@@ -32,7 +32,7 @@ export interface SubagentModelCandidate extends AllowedSubagentModel {
32
32
  selected: boolean;
33
33
  }
34
34
  /** State rendered by the staged allowlist card. */
35
- export interface SubagentModelSelectionCardState extends CardShell {
35
+ export interface SubagentModelSelectionCardState extends SettingsFormShell {
36
36
  /** Whether the draft enables model-facing child route selection. */
37
37
  enabled: boolean;
38
38
  /** Live catalog joined with stored routes. */
@@ -11,7 +11,7 @@
11
11
  import type { Context as ClientContext } from '@qilin-agent/kylin';
12
12
  import type { SnapshotStore } from '@qilin-agent/client-store';
13
13
  import type { ConfigForm } from '@qilin-agent/client-ui-settings/client';
14
- import { type CardActions, type CardFieldState, type CardShell } from './card-form.ts';
14
+ import { type SettingsFormActions, type SettingsFieldState, type SettingsFormShell } from '@qilin-agent/client-ui-primitives';
15
15
  /**
16
16
  * Namespace of the DeepSeek search provider. Spelled here rather than
17
17
  * imported: a client package must not depend on a Host package.
@@ -27,20 +27,20 @@ export interface WebSearchSettings {
27
27
  maxUses?: number;
28
28
  }
29
29
  /** What the web-search card renders. */
30
- export interface WebSearchCardState extends CardShell {
30
+ export interface WebSearchCardState extends SettingsFormShell {
31
31
  /** Provider endpoint. */
32
- baseURL: CardFieldState;
32
+ baseURL: SettingsFieldState;
33
33
  /** Searches allowed per request. */
34
- maxUses: CardFieldState;
34
+ maxUses: SettingsFieldState;
35
35
  /** The staged credential, which starts blank on every load. */
36
- apiKey: CardFieldState;
36
+ apiKey: SettingsFieldState;
37
37
  /** Whether the Host reports a credential configured for the referenced key. */
38
38
  apiKeyConfigured: boolean;
39
39
  /** Whether the credentials domain accepts a write for it; false disables the control. */
40
40
  apiKeyWritable: boolean;
41
41
  }
42
42
  /** The registration-side face the web-search card's slot entry injects. */
43
- export interface WebSearchCardFace extends CardActions {
43
+ export interface WebSearchCardFace extends SettingsFormActions {
44
44
  hooks: {
45
45
  /** Card snapshot bound by the renderer as useWebSearchCard. */
46
46
  webSearchCard: SnapshotStore<WebSearchCardState>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@qilin-agent/client-ui-settings-plugins",
3
3
  "description": "Plugins settings section with feature-owned tabs and configurable host-plane plugin cards",
4
- "version": "3.1.3",
4
+ "version": "3.1.4",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -47,15 +47,15 @@
47
47
  "clsx": "^2.0.0",
48
48
  "react": "^18.2.0",
49
49
  "@qilin-agent/kylin": "~4.0.3",
50
- "@qilin-agent/api-remotes": "3.1.3",
51
- "@qilin-agent/client-locale": "3.1.3",
52
- "@qilin-agent/client-store": "3.1.3",
53
- "@qilin-agent/client-ui-plugin-manager": "3.1.3",
54
- "@qilin-agent/client-test-runtime": "3.1.3",
55
- "@qilin-agent/client-ui-primitives": "3.1.3",
56
- "@qilin-agent/client-ui-renderer": "3.1.3",
57
- "@qilin-agent/client-ui-slots": "3.1.3",
58
- "@qilin-agent/client-ui-settings": "3.1.3"
50
+ "@qilin-agent/api-remotes": "3.1.4",
51
+ "@qilin-agent/client-test-runtime": "3.1.4",
52
+ "@qilin-agent/client-store": "3.1.4",
53
+ "@qilin-agent/client-locale": "3.1.4",
54
+ "@qilin-agent/client-ui-plugin-manager": "3.1.4",
55
+ "@qilin-agent/client-ui-primitives": "3.1.4",
56
+ "@qilin-agent/client-ui-renderer": "3.1.4",
57
+ "@qilin-agent/client-ui-settings": "3.1.4",
58
+ "@qilin-agent/client-ui-slots": "3.1.4"
59
59
  },
60
60
  "files": [
61
61
  "lib/index.js",
@@ -1,171 +0,0 @@
1
- /**
2
- * Shared form model behind every plugin card.
3
- *
4
- * A card stages what the user types and writes it only when they save. Each
5
- * settings write is a durable, revision-fenced document mutation, so a control
6
- * that committed as it settled turned one edit into a write the user never
7
- * asked for and could not preview; staged text makes what is on screen exactly
8
- * what a save would store.
9
- *
10
- * A field shows its effective value — the user layer over the composition
11
- * layer over the schema default — and whether the user layer carries it. That
12
- * presence, not a value comparison, is what marks a field overridden: an
13
- * override equal to the composition default is still an override.
14
- */
15
- import { type SnapshotStore } from '@qilin-agent/client-store';
16
- import type { ConfigForm } from '@qilin-agent/client-ui-settings/client';
17
- /** The write one field's staged text performs when the card is saved. */
18
- export type FieldWrite = {
19
- kind: 'set';
20
- value: unknown;
21
- } | {
22
- kind: 'clear';
23
- };
24
- /** How one section field converts between its stored value and its draft text. */
25
- export interface CardFieldSpec {
26
- /** Field name inside the namespace section. */
27
- field: string;
28
- /** Render a stored value as draft text; the empty string when the section carries none. */
29
- format: (value: unknown) => string;
30
- /**
31
- * The write this draft text stages, or undefined when the text is not a
32
- * value this field accepts — which blocks the save rather than discarding it.
33
- */
34
- parse: (text: string) => FieldWrite | undefined;
35
- }
36
- /**
37
- * A control whose value is written outside the settings section. A credential
38
- * literal never rides a response, so its draft has nothing to seed from: it is
39
- * blank until typed, and a blank draft writes nothing.
40
- */
41
- export interface CardSecretSpec {
42
- /** Field name addressing this control inside the card's form. */
43
- field: string;
44
- /** Write the staged text; resolves to whether the Host accepted it. */
45
- write: (text: string) => Promise<boolean>;
46
- }
47
- /** One field as a card's control renders it. */
48
- export interface CardFieldState {
49
- /** Draft text the control renders. */
50
- text: string;
51
- /**
52
- * Whether saving would leave a user-layer entry for this field. A staged
53
- * edit answers for itself, so the badge previews the save rather than
54
- * reporting a state the pending edit already contradicts.
55
- */
56
- overridden: boolean;
57
- /** Whether the draft is not a value this field accepts, which blocks saving. */
58
- invalid: boolean;
59
- }
60
- /** Form state every plugin card shares. */
61
- export interface CardShell {
62
- /** False while the namespace is not served to this client; the card renders nothing. */
63
- available: boolean;
64
- /** Whether the Host document accepts writes. */
65
- writable: boolean;
66
- /** Whether the form holds edits that a save would write. */
67
- dirty: boolean;
68
- /** Whether any staged draft is invalid, which blocks the save. */
69
- invalid: boolean;
70
- /** Whether a save is crossing the wire. */
71
- saving: boolean;
72
- /** Whether the last save did not land as staged; cleared by the next edit or save. */
73
- failed: boolean;
74
- }
75
- /** The write actions every plugin card's slot entry injects. */
76
- export interface CardActions {
77
- /** Stage draft text for one field. */
78
- edit: (field: string, text: string) => void;
79
- /** Stage a clear, so saving lets the field re-inherit the composition layer. */
80
- resetField: (field: string) => void;
81
- /** Write every staged edit, then re-seed from what the Host accepted. */
82
- save: () => void;
83
- /** Drop every staged edit. */
84
- discard: () => void;
85
- }
86
- /**
87
- * A whole-number field. An empty draft clears the field; any other draft that
88
- * is not a finite number blocks the save.
89
- * @param field - field name inside the namespace section.
90
- * @returns the field's conversion spec.
91
- */
92
- export declare function numberField(field: string): CardFieldSpec;
93
- /**
94
- * A free-text field. An empty draft clears the field, so emptying the control
95
- * and saving is the same gesture as resetting it.
96
- * @param field - field name inside the namespace section.
97
- * @returns the field's conversion spec.
98
- */
99
- export declare function textField(field: string): CardFieldSpec;
100
- /**
101
- * Stages one card's edits over one settings namespace and writes them on save.
102
- *
103
- * The form publishes through a snapshot store because slot components read
104
- * through a snapshot selector, while both the scope and the local drafts
105
- * change underneath; every projection is rebuilt from the two together.
106
- */
107
- export declare class CardForm<T> {
108
- private readonly scope;
109
- private readonly specs;
110
- private readonly secretSpecs;
111
- private readonly staged;
112
- private readonly listeners;
113
- private saving;
114
- private failed;
115
- /**
116
- * @param scope - the bound settings scope for this card's namespace.
117
- * @param specs - the section fields this card edits.
118
- * @param secrets - the card's write-only controls, written outside the section.
119
- */
120
- constructor(scope: ConfigForm<T>, specs: CardFieldSpec[], secrets?: CardSecretSpec[]);
121
- /**
122
- * Publish a projection of this form, rebuilt whenever the scope or a draft changes.
123
- * @param project - build the card's state from the form's current reads.
124
- * @returns the store the card's component reads through its bound selector.
125
- */
126
- bind<S>(project: () => S): SnapshotStore<S>;
127
- /**
128
- * Read the card-level state: what the Host serves, and what a save would do.
129
- * @returns the form state every card shares.
130
- */
131
- shell(): CardShell;
132
- /**
133
- * Read one control's state.
134
- * @param field - field name of a section field or of a write-only control.
135
- * @returns the draft text, whether a save would leave an override, and whether it is invalid.
136
- */
137
- field(field: string): CardFieldState;
138
- /**
139
- * Build the edit, reset, save, and discard actions bound to this form.
140
- * @returns the actions a card's slot entry injects.
141
- */
142
- actions(): CardActions;
143
- /**
144
- * Write every staged edit, then re-seed from what the Host accepted.
145
- *
146
- * The Host is the only authority on whether a value was accepted — its
147
- * validators own the constraints no schema can express — so the outcome is
148
- * read back from the section rather than predicted here. A save that did not
149
- * land keeps its drafts, so the user can correct them instead of retyping.
150
- * @returns settlement after every write and the read-back.
151
- */
152
- save(): Promise<void>;
153
- /**
154
- * Every staged edit a save would write. An entry whose draft is not a value
155
- * its field accepts carries no write: the form is still dirty, and the save
156
- * refuses rather than dropping the edit.
157
- * @returns the planned writes, in the order the fields were staged.
158
- */
159
- private plan;
160
- private clear;
161
- private store;
162
- private stage;
163
- private spec;
164
- private snapshotOf;
165
- private sectionValue;
166
- private baseValue;
167
- private userLayer;
168
- private stored;
169
- private publish;
170
- }
171
- //# sourceMappingURL=card-form.d.ts.map
@@ -1,69 +0,0 @@
1
- /**
2
- * Hand-written controls for the plugin configuration forms. Each renders one
3
- * field's label, its staged text, whether saving would leave an override, and
4
- * — when one stands — the reset that stages a clear back to the composition
5
- * layer. Nothing here writes: a control reports what the user typed, and the
6
- * card's save is the single point where a draft becomes a document mutation.
7
- */
8
- import { type ReactNode } from 'react';
9
- /** What every field control needs regardless of its value type. */
10
- export interface FieldProps {
11
- /** Stable id associating the label with its control. */
12
- id: string;
13
- /** Visible label. */
14
- label: string;
15
- /** One-line explanation rendered under the control. */
16
- hint: string;
17
- /** Draft text this control renders. */
18
- text: string;
19
- /** True when saving would leave a user-layer entry for this field. */
20
- overridden: boolean;
21
- /** True when the draft is not a value this field accepts. */
22
- invalid: boolean;
23
- /** Copy for the overridden badge. */
24
- overriddenLabel: string;
25
- /** Copy for the reset control. */
26
- resetLabel: string;
27
- /** Copy shown in place of the hint while the draft is invalid. */
28
- invalidLabel: string;
29
- /** Disables every control (read-only document, or an unavailable namespace). */
30
- disabled: boolean;
31
- /** Stage draft text. */
32
- onEdit: (text: string) => void;
33
- /** Stage a clear so the field re-inherits the composition layer. */
34
- onReset: () => void;
35
- }
36
- /**
37
- * A staged value field. `numeric` only hints the keypad: which drafts a field
38
- * accepts is decided by its spec, so the control never silently rewrites what
39
- * the user typed.
40
- * @param props - the field's copy, its staged text, and the edit actions.
41
- * @returns the labelled control.
42
- */
43
- export declare function ValueField(props: Omit<FieldProps, 'hint'> & {
44
- /** Optional explanation shown below the input. */
45
- hint?: string;
46
- /** Rules disclosed by the information button beside the label. */
47
- help?: {
48
- label: string;
49
- content: ReactNode;
50
- };
51
- /** Hints a numeric keypad without narrowing what the control accepts. */
52
- numeric?: boolean;
53
- /** Placeholder shown while the draft is empty. */
54
- placeholder?: string;
55
- }): import("react").JSX.Element;
56
- /**
57
- * A write-only credential control. The value never rides a response, so the
58
- * control reports only whether one is configured and starts blank; a blank
59
- * draft writes nothing, which keeps the stored key rather than clearing it.
60
- * @param props - the field's copy, its staged text, and the configured state.
61
- * @returns the labelled control.
62
- */
63
- export declare function SecretField(props: Pick<FieldProps, 'id' | 'label' | 'hint' | 'text' | 'disabled' | 'onEdit'> & {
64
- /** Whether the Host reports a configured credential for this reference. */
65
- configured: boolean;
66
- /** Copy describing the configured state. */
67
- stateLabel: string;
68
- }): import("react").JSX.Element;
69
- //# sourceMappingURL=fields.d.ts.map