dsh-web-search-pro 0.2.0 → 0.2.3

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 (266) hide show
  1. package/CHANGELOG.md +179 -0
  2. package/README.md +197 -32
  3. package/assets/skills/dsh-web-search-pro/SKILL.md +14 -13
  4. package/assets/skills/dsh-web-search-pro/references/config.md +36 -0
  5. package/assets/skills/dsh-web-search-pro/references/sources.md +19 -4
  6. package/assets/skills/dsh-web-search-pro/references/troubleshooting.md +3 -1
  7. package/catalog/sources.v1.json +22 -12
  8. package/lib/actions/approval.js +50 -1
  9. package/lib/actions/approval.js.map +1 -1
  10. package/lib/actions/config.js +274 -0
  11. package/lib/actions/config.js.map +1 -0
  12. package/lib/actions/errors.js +8 -1
  13. package/lib/actions/errors.js.map +1 -1
  14. package/lib/actions/format.js +10 -0
  15. package/lib/actions/format.js.map +1 -1
  16. package/lib/actions/index-view.js +2 -2
  17. package/lib/actions/index-view.js.map +1 -1
  18. package/lib/actions/read.js +7 -3
  19. package/lib/actions/read.js.map +1 -1
  20. package/lib/actions/registry.js +3 -1
  21. package/lib/actions/registry.js.map +1 -1
  22. package/lib/actions/run.js +2 -2
  23. package/lib/actions/run.js.map +1 -1
  24. package/lib/actions/schema.js +18 -0
  25. package/lib/actions/schema.js.map +1 -1
  26. package/lib/actions/search.js +12 -6
  27. package/lib/actions/search.js.map +1 -1
  28. package/lib/actions/sources.js +116 -41
  29. package/lib/actions/sources.js.map +1 -1
  30. package/lib/actions/types.js +19 -1
  31. package/lib/actions/types.js.map +1 -1
  32. package/lib/browser-access.js +25 -0
  33. package/lib/browser-access.js.map +1 -1
  34. package/lib/catalog/recommend.js +11 -3
  35. package/lib/catalog/recommend.js.map +1 -1
  36. package/lib/catalog/schema.js +3 -1
  37. package/lib/catalog/schema.js.map +1 -1
  38. package/lib/cli/builtin-specs.js +341 -0
  39. package/lib/cli/builtin-specs.js.map +1 -0
  40. package/lib/cli/chain.js +193 -0
  41. package/lib/cli/chain.js.map +1 -0
  42. package/lib/cli/chains-spec.js +118 -0
  43. package/lib/cli/chains-spec.js.map +1 -0
  44. package/lib/cli/engine.js +99 -0
  45. package/lib/cli/engine.js.map +1 -0
  46. package/lib/cli/opencli-sites.js +83 -0
  47. package/lib/cli/opencli-sites.js.map +1 -0
  48. package/lib/cli/opencli.js +153 -0
  49. package/lib/cli/opencli.js.map +1 -0
  50. package/lib/cli/probe.js +128 -0
  51. package/lib/cli/probe.js.map +1 -0
  52. package/lib/cli/runner.js +564 -0
  53. package/lib/cli/runner.js.map +1 -0
  54. package/lib/cli/spec.js +496 -0
  55. package/lib/cli/spec.js.map +1 -0
  56. package/lib/cli/time-text.js +79 -0
  57. package/lib/cli/time-text.js.map +1 -0
  58. package/lib/cli/trial.js +57 -0
  59. package/lib/cli/trial.js.map +1 -0
  60. package/lib/client/SettingsCard.js +14 -32
  61. package/lib/client/SettingsCard.js.map +1 -1
  62. package/lib/client/agent-mark.js +27 -0
  63. package/lib/client/agent-mark.js.map +1 -0
  64. package/lib/client/card-frame.js +118 -0
  65. package/lib/client/card-frame.js.map +1 -0
  66. package/lib/client/cli-form.js +257 -0
  67. package/lib/client/cli-form.js.map +1 -0
  68. package/lib/client/field-docs.js +130 -0
  69. package/lib/client/field-docs.js.map +1 -0
  70. package/lib/client/field-keys.js +81 -0
  71. package/lib/client/field-keys.js.map +1 -0
  72. package/lib/client/field-rows.js +71 -0
  73. package/lib/client/field-rows.js.map +1 -0
  74. package/lib/client/fill.js +3 -0
  75. package/lib/client/fill.js.map +1 -0
  76. package/lib/client/form-specs.js +15 -1
  77. package/lib/client/form-specs.js.map +1 -1
  78. package/lib/client/form.js +296 -27
  79. package/lib/client/form.js.map +1 -1
  80. package/lib/client/group-advanced.js +23 -0
  81. package/lib/client/group-advanced.js.map +1 -0
  82. package/lib/client/group-agent.js +28 -0
  83. package/lib/client/group-agent.js.map +1 -0
  84. package/lib/client/group-cli.js +136 -0
  85. package/lib/client/group-cli.js.map +1 -0
  86. package/lib/client/group-common.js +29 -0
  87. package/lib/client/group-common.js.map +1 -0
  88. package/lib/client/group-judge.js +67 -0
  89. package/lib/client/group-judge.js.map +1 -0
  90. package/lib/client/group-order.js +201 -0
  91. package/lib/client/group-order.js.map +1 -0
  92. package/lib/client/group-runtime.js +33 -0
  93. package/lib/client/group-runtime.js.map +1 -0
  94. package/lib/client/group-sources.js +83 -0
  95. package/lib/client/group-sources.js.map +1 -0
  96. package/lib/client/groups-basic.js +36 -0
  97. package/lib/client/groups-basic.js.map +1 -0
  98. package/lib/client/index.js.map +1 -1
  99. package/lib/client/json-list.js +50 -0
  100. package/lib/client/json-list.js.map +1 -0
  101. package/lib/client/locales.js +666 -215
  102. package/lib/client/locales.js.map +1 -1
  103. package/lib/client/order.js +192 -0
  104. package/lib/client/order.js.map +1 -0
  105. package/lib/client/overlay-ops.js +46 -0
  106. package/lib/client/overlay-ops.js.map +1 -0
  107. package/lib/client/sources-table.js +1 -0
  108. package/lib/client/sources-table.js.map +1 -1
  109. package/lib/client/styles.js +74 -47
  110. package/lib/client/styles.js.map +1 -1
  111. package/lib/client/text-view.js +98 -0
  112. package/lib/client/text-view.js.map +1 -0
  113. package/lib/client/ui-kit.js +120 -0
  114. package/lib/client/ui-kit.js.map +1 -0
  115. package/lib/client/validators.js +22 -0
  116. package/lib/client/validators.js.map +1 -1
  117. package/lib/client.js +9151 -1987
  118. package/lib/client.js.map +1 -1
  119. package/lib/config-fillers.js +53 -0
  120. package/lib/config-fillers.js.map +1 -0
  121. package/lib/config-groups.js +49 -0
  122. package/lib/config-groups.js.map +1 -0
  123. package/lib/config.js +87 -107
  124. package/lib/config.js.map +1 -1
  125. package/lib/default-chain.js +66 -0
  126. package/lib/default-chain.js.map +1 -0
  127. package/lib/deps.js +109 -102
  128. package/lib/deps.js.map +1 -1
  129. package/lib/engine-error.js +19 -0
  130. package/lib/engine-error.js.map +1 -0
  131. package/lib/engines.js +32 -115
  132. package/lib/engines.js.map +1 -1
  133. package/lib/fetch.js +23 -4
  134. package/lib/fetch.js.map +1 -1
  135. package/lib/index.js +30 -5
  136. package/lib/index.js.map +1 -1
  137. package/lib/overlay-types.js +88 -0
  138. package/lib/overlay-types.js.map +1 -0
  139. package/lib/overlay.js +683 -0
  140. package/lib/overlay.js.map +1 -0
  141. package/lib/pipeline/candidates.js +27 -1
  142. package/lib/pipeline/candidates.js.map +1 -1
  143. package/lib/pipeline/compile.js +63 -0
  144. package/lib/pipeline/compile.js.map +1 -1
  145. package/lib/pipeline/confidence.js +64 -0
  146. package/lib/pipeline/confidence.js.map +1 -0
  147. package/lib/pipeline/fusion.js +50 -3
  148. package/lib/pipeline/fusion.js.map +1 -1
  149. package/lib/pipeline/plan.js +2 -2
  150. package/lib/pipeline/plan.js.map +1 -1
  151. package/lib/pipeline/render.js +20 -2
  152. package/lib/pipeline/render.js.map +1 -1
  153. package/lib/pipeline/run.js +21 -7
  154. package/lib/pipeline/run.js.map +1 -1
  155. package/lib/pipeline/sources-spec.js +19 -3
  156. package/lib/pipeline/sources-spec.js.map +1 -1
  157. package/lib/providers/builtin.js +13 -14
  158. package/lib/providers/builtin.js.map +1 -1
  159. package/lib/providers/deepseek.js +348 -0
  160. package/lib/providers/deepseek.js.map +1 -0
  161. package/lib/providers/http.js.map +1 -1
  162. package/lib/providers/keyed-meta.js +7 -0
  163. package/lib/providers/keyed-meta.js.map +1 -1
  164. package/lib/providers/platforms.js +118 -58
  165. package/lib/providers/platforms.js.map +1 -1
  166. package/lib/providers/registry.js.map +1 -1
  167. package/lib/restart.js +47 -0
  168. package/lib/restart.js.map +1 -0
  169. package/lib/router.js +203 -27
  170. package/lib/router.js.map +1 -1
  171. package/lib/rpc-types.js +15 -0
  172. package/lib/rpc-types.js.map +1 -0
  173. package/lib/rpc.js +85 -0
  174. package/lib/rpc.js.map +1 -0
  175. package/lib/tools.js +10 -4
  176. package/lib/tools.js.map +1 -1
  177. package/lib/types/actions/approval.d.ts +11 -0
  178. package/lib/types/actions/config.d.ts +54 -0
  179. package/lib/types/actions/format.d.ts +9 -2
  180. package/lib/types/actions/run.d.ts +1 -0
  181. package/lib/types/actions/schema.d.ts +7 -1
  182. package/lib/types/actions/sources.d.ts +29 -3
  183. package/lib/types/actions/types.d.ts +28 -2
  184. package/lib/types/browser-access.d.ts +17 -0
  185. package/lib/types/catalog/recommend.d.ts +4 -0
  186. package/lib/types/catalog/schema.d.ts +2 -0
  187. package/lib/types/cli/builtin-specs.d.ts +38 -0
  188. package/lib/types/cli/chain.d.ts +83 -0
  189. package/lib/types/cli/chains-spec.d.ts +48 -0
  190. package/lib/types/cli/engine.d.ts +50 -0
  191. package/lib/types/cli/opencli-sites.d.ts +24 -0
  192. package/lib/types/cli/opencli.d.ts +77 -0
  193. package/lib/types/cli/probe.d.ts +53 -0
  194. package/lib/types/cli/runner.d.ts +126 -0
  195. package/lib/types/cli/spec.d.ts +269 -0
  196. package/lib/types/cli/time-text.d.ts +12 -0
  197. package/lib/types/cli/trial.d.ts +19 -0
  198. package/lib/types/client/SettingsCard.d.ts +17 -1
  199. package/lib/types/client/agent-mark.d.ts +22 -0
  200. package/lib/types/client/card-frame.d.ts +35 -0
  201. package/lib/types/client/cli-form.d.ts +97 -0
  202. package/lib/types/client/field-docs.d.ts +15 -0
  203. package/lib/types/client/field-keys.d.ts +41 -0
  204. package/lib/types/client/field-rows.d.ts +70 -0
  205. package/lib/types/client/fill.d.ts +2 -0
  206. package/lib/types/client/form-specs.d.ts +12 -3
  207. package/lib/types/client/form.d.ts +79 -1
  208. package/lib/types/client/group-advanced.d.ts +9 -0
  209. package/lib/types/client/group-agent.d.ts +20 -0
  210. package/lib/types/client/group-cli.d.ts +52 -0
  211. package/lib/types/client/group-common.d.ts +12 -0
  212. package/lib/types/client/group-judge.d.ts +17 -0
  213. package/lib/types/client/group-order.d.ts +26 -0
  214. package/lib/types/client/group-runtime.d.ts +15 -0
  215. package/lib/types/client/group-sources.d.ts +46 -0
  216. package/lib/types/client/groups-basic.d.ts +18 -0
  217. package/lib/types/client/index.d.ts +8 -0
  218. package/lib/types/client/json-list.d.ts +21 -0
  219. package/lib/types/client/locales.d.ts +1079 -196
  220. package/lib/types/client/order.d.ts +102 -0
  221. package/lib/types/client/overlay-ops.d.ts +37 -0
  222. package/lib/types/client/styles.d.ts +56 -41
  223. package/lib/types/client/text-view.d.ts +22 -0
  224. package/lib/types/client/ui-kit.d.ts +200 -0
  225. package/lib/types/client/validators.d.ts +6 -0
  226. package/lib/types/config-fillers.d.ts +9 -0
  227. package/lib/types/config-groups.d.ts +23 -0
  228. package/lib/types/config.d.ts +265 -216
  229. package/lib/types/default-chain.d.ts +63 -0
  230. package/lib/types/deps.d.ts +25 -23
  231. package/lib/types/engine-error.d.ts +12 -0
  232. package/lib/types/engines.d.ts +45 -10
  233. package/lib/types/fetch.d.ts +12 -3
  234. package/lib/types/index.d.ts +164 -146
  235. package/lib/types/overlay-types.d.ts +98 -0
  236. package/lib/types/overlay.d.ts +141 -0
  237. package/lib/types/pipeline/candidates.d.ts +19 -0
  238. package/lib/types/pipeline/compile.d.ts +11 -0
  239. package/lib/types/pipeline/confidence.d.ts +35 -0
  240. package/lib/types/pipeline/fusion.d.ts +23 -1
  241. package/lib/types/pipeline/render.d.ts +16 -0
  242. package/lib/types/pipeline/run.d.ts +3 -1
  243. package/lib/types/pipeline/sources-spec.d.ts +5 -2
  244. package/lib/types/pipeline/types.d.ts +37 -0
  245. package/lib/types/providers/deepseek.d.ts +130 -0
  246. package/lib/types/providers/http.d.ts +2 -1
  247. package/lib/types/providers/keyed-meta.d.ts +5 -0
  248. package/lib/types/providers/platforms.d.ts +15 -3
  249. package/lib/types/providers/registry.d.ts +10 -0
  250. package/lib/types/restart.d.ts +52 -0
  251. package/lib/types/router.d.ts +69 -9
  252. package/lib/types/rpc-types.d.ts +79 -0
  253. package/lib/types/rpc.d.ts +41 -0
  254. package/lib/types/tools.d.ts +6 -0
  255. package/lib/types/util.d.ts +16 -1
  256. package/lib/util.js +17 -4
  257. package/lib/util.js.map +1 -1
  258. package/package.json +51 -43
  259. package/scripts/check-client-bundle.mjs +1 -1
  260. package/scripts/cli-login-check.mjs +214 -0
  261. package/lib/client/RubricEditor.js +0 -47
  262. package/lib/client/RubricEditor.js.map +0 -1
  263. package/lib/client/fields.js +0 -31
  264. package/lib/client/fields.js.map +0 -1
  265. package/lib/types/client/RubricEditor.d.ts +0 -6
  266. package/lib/types/client/fields.d.ts +0 -65
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Declarative CLI adapter spec (dev-plan M12): what a standalone command-line tool is, which of its commands the plugin
3
+ * may run, and how its output maps to search sources. Pure data plus validation, no Node imports, so the settings card
4
+ * (client bundle) validates `cliAdapters` with the very function the server uses.
5
+ *
6
+ * The read-only guarantee lives here and applies to built-in and user-defined specs alike:
7
+ * - argv is an array of tokens, never a shell string (the runner spawns without a shell);
8
+ * - a spec declares `allowedSubcommands`, and every command word its argv uses (the leading literal tokens before the
9
+ * first flag or placeholder) must be in that list;
10
+ * - no command word, declared subcommand or flag may match the global deny-list (login, post, delete*, like, ...,
11
+ * and the flags that make a CLI read browser cookies or carry secrets in argv).
12
+ * @module web-search-pro/cli/spec
13
+ */
14
+ export declare const OUTPUT_FORMATS: readonly ["json", "ndjson", "yaml", "text"];
15
+ export type OutputFormat = typeof OUTPUT_FORMATS[number];
16
+ /** How far a spec has been checked against the real tool (recorded in the spec and shown in `sources.status`). */
17
+ export declare const CLI_VERIFICATIONS: readonly ["live", "contract-only", "docs-only"];
18
+ export type CliVerification = typeof CLI_VERIFICATIONS[number];
19
+ /**
20
+ * The short honest tag shown next to a backend that was not verified with a real search ("detected and configured" is not "works"),
21
+ * or undefined for `live` and for backends that are not CLI specs.
22
+ */
23
+ export declare function verificationTag(status: string): string | undefined;
24
+ /** The verification word of a user-defined spec: it is unverified by definition and says so in every result it returns. */
25
+ export declare const USER_DEFINED = "user-defined";
26
+ /** The honest label a custom CLI's results and chain entries carry. */
27
+ export declare const USER_DEFINED_TAG = "user-defined, not verified by the plugin (\u7528\u6237\u81EA\u5B9A\u4E49\uFF0C\u672A\u7ECF\u63D2\u4EF6\u9A8C\u8BC1)";
28
+ /** Confidence of a custom CLI whose spec gives none: below the built-in sources (1), because nothing here checked its output. */
29
+ export declare const DEFAULT_CUSTOM_CONFIDENCE = 0.5;
30
+ /** Default and largest size of a whole-output result's text, in characters (`output.lines.maxChars`). */
31
+ export declare const WHOLE_OUTPUT_DEFAULT_CHARS = 2000;
32
+ export declare const WHOLE_OUTPUT_MAX_CHARS = 8000;
33
+ /** Scheme of the stand-in link of a whole-output result (`cli://<id>?q=<query>`): not a web page, so nothing fetches it. */
34
+ export declare const WHOLE_OUTPUT_SCHEME = "cli://";
35
+ export declare const CLI_ERROR_CODES: readonly ["CLI_NOT_FOUND", "CLI_CONTRACT_MISMATCH", "CLI_NOT_LOGGED_IN", "ENGINE_EMPTY", "CLI_FAILED"];
36
+ export type CliErrorCode = typeof CLI_ERROR_CODES[number];
37
+ /**
38
+ * One piece of a joined field: a path, optionally with text put before / after the value, a `{ template }` over the item (dropped
39
+ * when a placeholder is empty), or a `{ time }` path whose text is read as a time (see {@link FieldSource}) and dropped when it is not one.
40
+ */
41
+ export type JoinPart = string | {
42
+ path: string;
43
+ prefix?: string;
44
+ suffix?: string;
45
+ } | {
46
+ template: string;
47
+ } | {
48
+ time: string;
49
+ prefix?: string;
50
+ suffix?: string;
51
+ };
52
+ /** `{ template }` fills `{path}` placeholders from the item and yields nothing when one is empty; `when` makes it apply to one kind of item. */
53
+ export interface TemplateSource {
54
+ template: string;
55
+ when?: {
56
+ path: string;
57
+ equals: string | number | boolean;
58
+ };
59
+ }
60
+ /**
61
+ * Where a field of a source comes from, for one parsed item:
62
+ * - a dotted path (`data.title`, `items.0.url`);
63
+ * - a list of paths and templates: the first non-empty one wins;
64
+ * - `{ template }`: `{path}` placeholders over the item, dropped when any of them is empty;
65
+ * - `{ join }`: the non-empty parts joined with `sep` (default ` | `);
66
+ * - `{ epoch }`: a Unix timestamp (seconds) as an ISO date; `{ date }`: the date part (first 10 characters) of an ISO timestamp;
67
+ * - `{ time }`: a time text the tool prints (ISO, the X API's `created_at`, `2026-10-27`, `08-26`, `3小时前`, `昨天 10:20`, ...) as an
68
+ * ISO date or timestamp, and nothing when the text is none of the exactly known formats (see cli/time-text.ts).
69
+ * A dotted path may hold a `key=value` segment that picks the first element of an array with that field value
70
+ * (`note_card.corner_tag_info.type=publish_time.text`).
71
+ */
72
+ export type FieldSource = string | readonly (string | TemplateSource)[] | TemplateSource | {
73
+ join: readonly JoinPart[];
74
+ sep?: string;
75
+ } | {
76
+ epoch: string;
77
+ } | {
78
+ date: string;
79
+ } | {
80
+ time: string;
81
+ };
82
+ export interface CliOutputSpec {
83
+ format: OutputFormat;
84
+ /** json / yaml: dotted path of the item array; absent = the root array, else the first array-valued property. */
85
+ itemsPath?: string;
86
+ /** json / yaml: every entry must hold, else the output is a failure (a versioned envelope's `ok` and `schema_version`). */
87
+ expect?: readonly {
88
+ path: string;
89
+ equals: string | number | boolean;
90
+ }[];
91
+ /** Paths of the tool's own error text, read when `expect` fails (first non-empty one). */
92
+ errorPaths?: readonly string[];
93
+ /**
94
+ * text: how a line becomes an item (`tsv`: tab separated columns; `url-lines`: lines holding a URL, `url` + `title`; `whole`: the
95
+ * whole stdout is ONE result, for a tool that prints just a block of text: its text capped at `maxChars` (default
96
+ * {@link WHOLE_OUTPUT_DEFAULT_CHARS}) with a note when it was cut, the title "<id>: <query>" and the link `cli://<id>?q=<query>`).
97
+ */
98
+ lines?: {
99
+ mode: 'tsv';
100
+ columns: readonly string[];
101
+ } | {
102
+ mode: 'url-lines';
103
+ } | {
104
+ mode: 'whole';
105
+ maxChars?: number;
106
+ };
107
+ /** Required (with `url`) for every mode except `whole`, which maps nothing. */
108
+ fields?: {
109
+ url?: FieldSource;
110
+ title?: FieldSource;
111
+ snippet?: FieldSource;
112
+ publishedAt?: FieldSource;
113
+ };
114
+ /** Items whose `path` equals the value are not results at all and are not counted as skipped (xhs: `model_type` is `hot_query` for the suggestion cards its result list also carries). */
115
+ skipWhen?: {
116
+ path: string;
117
+ equals: string | number | boolean;
118
+ };
119
+ /** Strip HTML tags from title and snippet. */
120
+ stripTags?: boolean;
121
+ /** Values read as "empty" (`None`). */
122
+ emptyValues?: readonly string[];
123
+ /** Longest snippet kept (default 400). */
124
+ snippetMax?: number;
125
+ /** Longest title kept (default 300). */
126
+ titleMax?: number;
127
+ /** Drop items without a title (a line that is not a result). */
128
+ requireTitle?: boolean;
129
+ }
130
+ /**
131
+ * How a tool reports a failed command in its machine-readable format (a YAML / JSON payload on stderr, else stdout), and what
132
+ * each of its error codes means. A listed code is mapped to a structured plugin error; a code that is not listed keeps the
133
+ * tool's own message (`<tool> search failed: [CODE] message`).
134
+ */
135
+ export interface CliErrorCodesSpec {
136
+ /** Dotted path of the tool's error code in the failure payload (`error.code`). */
137
+ codePath: string;
138
+ /** Dotted path of its message (`error.message`). */
139
+ messagePath?: string;
140
+ /** Codes that mean "not logged in" (CLI_NOT_LOGGED_IN). */
141
+ notLoggedIn?: readonly string[];
142
+ /** Exit codes that mean "not logged in" when the output carries no readable code. */
143
+ notLoggedInExit?: readonly number[];
144
+ /** Codes that mean "no results" (ENGINE_EMPTY). */
145
+ empty?: readonly string[];
146
+ /** Codes that mean the site answered with a web page or blocked the request: risk control, IP block, login wall (CLI_FAILED, said so). */
147
+ blocked?: readonly string[];
148
+ /** Case-insensitive fragments of the tool's message that mean the same (a JSON parse error on an HTML page: `Unexpected token '<'`). */
149
+ blockedPatterns?: readonly string[];
150
+ /** Codes that mean the tool cannot reach its browser (CLI_FAILED, not retryable). */
151
+ unavailable?: readonly string[];
152
+ /** Codes that mean a timeout (ENGINE_TIMEOUT). */
153
+ timeout?: readonly string[];
154
+ /** Codes that mean the tool rejected its arguments (CLI_CONTRACT_MISMATCH: the adapter does not match this version). */
155
+ usage?: readonly string[];
156
+ }
157
+ export interface CliSearchSpec {
158
+ /**
159
+ * Arguments after the binary. `{query}` and `{count}` are the placeholders; a token may embed one (`ytsearch{count}:{query}`).
160
+ * A token that is exactly `{terms}` expands to the query split into one argv token per word (double quotes keep a phrase together):
161
+ * for tools that join their positional arguments themselves and would otherwise quote a one-token query as an exact phrase (`gh search`).
162
+ */
163
+ argv: readonly string[];
164
+ /** Largest `{count}` sent (the search call's count is clamped to 1..maxCount). */
165
+ maxCount?: number;
166
+ /**
167
+ * Extra results asked of the tool beyond the count (`{count}` becomes count + overfetch), for tools whose list can hold entries the
168
+ * mapper must drop (bili: courses and series without a link). The mapper still returns at most `count`.
169
+ */
170
+ overfetch?: number;
171
+ output: CliOutputSpec;
172
+ /** Case-insensitive fragments of the tool's output that mean "no results" rather than a failure. */
173
+ emptyWhen?: readonly string[];
174
+ /** Case-insensitive fragments of the tool's output that mean "not logged in" (maps to CLI_NOT_LOGGED_IN). */
175
+ notLoggedInPatterns?: readonly string[];
176
+ /** The tool's structured error codes (checked before the fragments above). */
177
+ errorCodes?: CliErrorCodesSpec;
178
+ }
179
+ export interface CliProbeSpec {
180
+ versionArgs: readonly string[];
181
+ /** `X.Y.Z` the detected version must reach. */
182
+ minVersion?: string;
183
+ helpArgs: readonly string[];
184
+ /** Fragments the help output must contain: the subcommands and flags that prove this is the tool the spec describes. */
185
+ mustContain: readonly string[];
186
+ /** Appended to the reason when `mustContain` is not met (which version is known to have the contract, for example). */
187
+ contractHint?: string;
188
+ }
189
+ export interface CliLoginSpec {
190
+ /** What the user runs themselves (`xhs login`); never run by the plugin. */
191
+ command?: string;
192
+ /** What the user does, in words, when the tool takes its login from somewhere the plugin cannot run (the login of the user's own Chrome): shown instead of a command. One of `command` / `hint` is required. */
193
+ hint?: string;
194
+ /** Home-relative files that exist once the user has logged in. Only their existence is checked, never their content. */
195
+ savedCredentialPaths?: readonly string[];
196
+ /** The tool reads the browser's cookies by itself when it has no saved login: then it is never run without one. */
197
+ readsBrowserCookiesWithoutLogin?: boolean;
198
+ }
199
+ export interface CliAdapterSpec {
200
+ id: string;
201
+ /** Command names tried in order on PATH. */
202
+ bins: readonly string[];
203
+ /** What the package is called, which can differ from the command (`pip install pyzhihu-cli` runs `zhihu`). */
204
+ packageNote: string;
205
+ /**
206
+ * Platform ids the spec serves: the platforms whose backend chain it may sit in (`platformBackends.<platform>`). A user spec is
207
+ * also a platform of its own, `custom-cli:<id>`, and may list none when it is a general `engine`.
208
+ */
209
+ platforms: readonly string[];
210
+ /** User specs only: also a general search engine, listed in `engines` as `custom-cli:<id>` (fused and de-duplicated with the others). */
211
+ engine?: boolean;
212
+ /** User specs only: 0..1, default {@link DEFAULT_CUSTOM_CONFIDENCE}. `sources.confidence.custom-cli:<id>` overrides it. */
213
+ confidence?: number;
214
+ probe: CliProbeSpec;
215
+ /** Every command word the argv templates use. */
216
+ allowedSubcommands: readonly string[];
217
+ search: CliSearchSpec;
218
+ /** Per-platform overrides of `search` (gh serves github, github-issues and github-code with different commands). */
219
+ searches?: Readonly<Record<string, CliSearchSpec>>;
220
+ read?: CliSearchSpec;
221
+ env: {
222
+ required?: readonly string[];
223
+ passthrough?: readonly string[];
224
+ set?: Readonly<Record<string, string>>;
225
+ };
226
+ needsLogin: boolean;
227
+ login?: CliLoginSpec;
228
+ timeoutMs: number;
229
+ maxOutputBytes: number;
230
+ /** Built-ins only: how far the spec was checked. User-defined specs carry none (they are unverified by definition). */
231
+ verification?: {
232
+ status: CliVerification;
233
+ version?: string;
234
+ date?: string;
235
+ note?: string;
236
+ };
237
+ }
238
+ /** Command words that write, log in, or change local or remote state. Matched exactly, or as `<word>-...` / `<word>_...`. */
239
+ export declare const DENIED_SUBCOMMANDS: readonly string[];
240
+ /** Command words denied by prefix alone (`delete`, `delete-note`, `deleteNote`, `remove...`). */
241
+ export declare const DENIED_PREFIXES: readonly string[];
242
+ /** Flags (without leading dashes) that read browser cookies or carry credentials in argv. */
243
+ export declare const DENIED_FLAGS: readonly string[];
244
+ /** The command words of an argv: leading literal tokens before the first flag or placeholder token. */
245
+ export declare function commandWords(argv: readonly string[]): string[];
246
+ /** Problems of one argv template with respect to the read-only guard (empty = fine). */
247
+ export declare function argvProblems(argv: readonly string[], allowed: readonly string[], where: string): string[];
248
+ export interface CliSpecValidation {
249
+ ok: boolean;
250
+ errors: string[];
251
+ spec?: CliAdapterSpec;
252
+ }
253
+ /**
254
+ * Validate one adapter spec (built-in or user-defined). Never throws. A user-defined spec (`origin: 'user'`) may not carry a
255
+ * `verification` (it is unverified by definition) and its `platforms` are ignored: it is registered as `custom-cli:<id>`.
256
+ */
257
+ export declare function validateCliAdapterSpec(raw: unknown, origin?: 'builtin' | 'user'): CliSpecValidation;
258
+ /** Validate the `cliAdapters` setting: the valid specs by id and the problems of the rest (an invalid entry is ignored, never fatal). */
259
+ export declare function resolveCliAdapters(input: unknown): {
260
+ specs: Map<string, CliAdapterSpec>;
261
+ diagnostics: string[];
262
+ };
263
+ /** Search spec of one platform: the platform's override, else the default. */
264
+ export declare function searchSpecFor(spec: CliAdapterSpec, platform: string): CliSearchSpec;
265
+ export declare function compareVersions(left: string, right: string): number;
266
+ /** The first `X.Y.Z` (or `X.Y`) in a tool's version output. */
267
+ export declare function parseVersion(output: string): string | undefined;
268
+ /** `platformBackends`: ordered backend ids per platform. Pure shape check; ids are checked against the known backends by the caller. */
269
+ export declare function platformBackendProblems(input: unknown): string[];
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Conservative parsing of the time texts CLI tools print (a field source `{ time }` of the adapter spec): an exact format is
3
+ * turned into an ISO date or timestamp, anything else gives nothing, so a result never carries a guessed time. Pure; the clock is
4
+ * a parameter. Chinese relative and calendar texts are read in China time (UTC+8), which is what the sites print.
5
+ * - ISO 8601 (`2026-10-27T08:38:08Z`, with or without a zone offset or fraction) -> normalized timestamp;
6
+ * - the `created_at` of the X API (`Tue Oct 27 08:38:08 +0000 2026`) -> timestamp;
7
+ * - `YYYY-MM-DD` -> that date; `MM-DD` -> the latest such date that is not after today (a date in the future means last year);
8
+ * - `N分钟前` / `N小时前` -> timestamp (now minus N); `N天前` -> date; `昨天 HH:MM` -> timestamp (China time).
9
+ * @module web-search-pro/cli/time-text
10
+ */
11
+ /** The text as an ISO date (`YYYY-MM-DD`) or timestamp, or undefined when it is not one of the formats above. */
12
+ export declare function normalizeTimeText(raw: string, now?: number): string | undefined;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The trial run of a custom CLI spec (settings card, "Try it"): what a search with the draft spec would do, shown before it is saved.
3
+ * It is a real run, not a simulation: the spec is validated by the rule every spec goes through (the read-only guard, no shell, no
4
+ * credentials in argv), the command is probed (version and help only), then ONE search for the sample query runs through the same
5
+ * runner with the spec's own timeout and output cap. The first results and the tool's own words come back; secrets are redacted,
6
+ * a login is never run, and nothing is stored.
7
+ * @module web-search-pro/cli/trial
8
+ */
9
+ import { type runCli } from '../util.ts';
10
+ import type { TrialResult } from '../rpc-types.ts';
11
+ export interface TrialOptions {
12
+ /** `enableCliBackends`: with it off no custom command runs, trial or search. */
13
+ enabled: boolean;
14
+ signal?: AbortSignal;
15
+ /** Test seams. */
16
+ run?: typeof runCli;
17
+ env?: NodeJS.ProcessEnv;
18
+ }
19
+ export declare function trialCli(id: string, rawSpec: unknown, query: string, options: TrialOptions): Promise<TrialResult>;
@@ -1,2 +1,18 @@
1
+ /**
2
+ * The Web Search Pro settings card, as the Plugins page renders it.
3
+ *
4
+ * The page owns the card frame (its title, disclosure and artwork come from the slot registration), so this component renders
5
+ * only what goes inside: the one-liner for `view: 'summary'`, and for `view: 'page'` a status summary, twelve groups (only
6
+ * "Common" open) and a save bar that stays in view.
7
+ *
8
+ * Common · Search order · Sources · Custom CLI · Reading and evidence · Scoring model · Built-in web tool route ·
9
+ * Runtime and backends · Network and cache · Ranking weights · Agent changes · Advanced: text mode and raw JSON
10
+ *
11
+ * Each group is its own module (`group-*.tsx`) built from the controls in `ui-kit.tsx`: the Host's own switches, buttons,
12
+ * badges, dialogs and help bubbles, plus the few controls the Host has no component for. Every public config field has
13
+ * exactly one entry in the groups (test/settings-card-render.test.ts counts them); the text of the last group is a view of
14
+ * the same fields, not a second place they live.
15
+ * @module web-search-pro/client/SettingsCard
16
+ */
1
17
  import type { SettingsCardProps } from './index.ts';
2
- export declare function SettingsCard(props: SettingsCardProps): string | import("react").JSX.Element | null;
18
+ export declare function SettingsCard(props: SettingsCardProps): import("react").JSX.Element;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The mark beside a setting that an agent changed with `config.*`: "Changed by agent", whose tooltip says what the agent set, what the
3
+ * configuration holds, why and when, and (outside the cramped list rows) the two buttons that settle it: adopt the value into the
4
+ * configuration, or revoke it. The data is the plugin's overlay, read once over the card's RPC channel when the panel opens and again
5
+ * on the refresh button (see group-agent.tsx).
6
+ * @module web-search-pro/client/agent-mark
7
+ */
8
+ import type { OverlayItem } from '../overlay-types.ts';
9
+ import type { Card } from './field-rows.tsx';
10
+ /** The overlay item of a key in the card's state, or undefined. */
11
+ export declare function useOverlayItem(card: Card, key: string): OverlayItem | undefined;
12
+ /** One sentence for the tooltip: the value the agent set, the one in the configuration, the reason, who and when. */
13
+ export declare function agentTip(t: Card['t'], item: OverlayItem): string;
14
+ /**
15
+ * `compact` shows the tag only (list rows have no room for buttons; the "Agent changes" group holds them); otherwise the tag is followed
16
+ * by "Adopt into configuration" and "Revoke".
17
+ */
18
+ export declare function AgentMark({ card, itemKey, compact }: {
19
+ card: Card;
20
+ itemKey: string;
21
+ compact?: boolean;
22
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The frame around the groups: the status summary on top (with the warnings dialog) and the save bar at the bottom.
3
+ *
4
+ * The Host's `SettingsForm` offers one save button below the controls. This card needs the bar to stay in view while a long
5
+ * page scrolls, to say how many edits are waiting, and to offer "Discard", so the frame is built here; the behaviors a
6
+ * settings form has are kept: it says so when the settings are not served or read-only, and it drops the staged edits when
7
+ * the page is left.
8
+ * @module web-search-pro/client/card-frame
9
+ */
10
+ import { type ReactNode } from 'react';
11
+ import { type ChainInput } from '../default-chain.ts';
12
+ import { type Card } from './field-rows.tsx';
13
+ import type { WebSearchCardState } from './form.ts';
14
+ /** What the default chain rule reads from the staged settings: the list, the preferences, the ready common sources, the policy. */
15
+ export declare function chainInputOf(snapshot: Pick<WebSearchCardState, 'fields' | 'credentials'>): ChainInput;
16
+ /** The chain a plain search would try, from the staged settings; undefined when the draft leaves nothing to try. */
17
+ export declare function chainOf(snapshot: Pick<WebSearchCardState, 'fields' | 'credentials'>): string[] | undefined;
18
+ /**
19
+ * The chain a plain search tries once the agent's changes (engines, priority, disabled of the overlay) are on top of the staged settings,
20
+ * by the same rule; undefined while the agent changed none of the three, an empty list when it would leave nothing to try.
21
+ */
22
+ export declare function agentChainOf(snapshot: Pick<WebSearchCardState, 'fields' | 'credentials' | 'server'>): string[] | undefined;
23
+ /** Everything the warnings badge counts: what the validation says about a field, and the rubric problems. */
24
+ export declare function warningsOf(snapshot: WebSearchCardState, t: Card['t']): string[];
25
+ export declare function SummaryBar({ card }: {
26
+ card: Card;
27
+ }): import("react").JSX.Element;
28
+ export declare function SaveBar({ card }: {
29
+ card: Card;
30
+ }): import("react").JSX.Element;
31
+ /** The page frame: nothing but a notice while the settings are not served; the staged edits are dropped when the page is left. */
32
+ export declare function Frame({ card, children }: {
33
+ card: Card;
34
+ children: ReactNode;
35
+ }): import("react").JSX.Element;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * The form side of the custom CLI editor: a `cliAdapters` entry (the JSON spec) as the fields of the edit dialog and back. Two
3
+ * views of one object: the form writes the keys it has controls for onto a copy of the spec and leaves every other key as it
4
+ * was (searches, read, env, login, errorCodes, a field mapping that is not a plain path), and the JSON box edits the whole spec.
5
+ * Validation is `validateCliAdapterSpec`, the function the server registers specs with; its messages are sorted to the field they
6
+ * are about. `allowedSubcommands` is derived from the command words of the argv templates, never typed.
7
+ * Pure: no Host, no DOM.
8
+ * @module web-search-pro/client/cli-form
9
+ */
10
+ import { WHOLE_OUTPUT_DEFAULT_CHARS, type OutputFormat } from '../cli/spec.ts';
11
+ type Json = Record<string, unknown>;
12
+ /** The result fields the form maps, in display order; each takes a dotted path into one item of the tool's output. */
13
+ export declare const FIELD_KEYS: readonly ["url", "title", "snippet", "publishedAt"];
14
+ export type FieldKey = typeof FIELD_KEYS[number];
15
+ /** How a plain text tool's lines become items (`whole` is a switch of its own). */
16
+ export declare const LINE_MODES: readonly ["url-lines", "tsv"];
17
+ export type LineMode = typeof LINE_MODES[number];
18
+ export interface CliForm {
19
+ /** The key in `cliAdapters` (`custom-cli:<id>` everywhere else). */
20
+ id: string;
21
+ /** The command: a name on PATH, never a path. */
22
+ bin: string;
23
+ /** The argument template, one token per entry; `{query}`, `{count}` and `{terms}` are filled in. */
24
+ argv: string[];
25
+ format: OutputFormat;
26
+ /** Text output only: the whole stdout is one result (no field mapping). */
27
+ whole: boolean;
28
+ wholeMax: string;
29
+ /** json / yaml: dotted path of the result array (empty = the root array or the first array found). */
30
+ itemsPath: string;
31
+ linesMode: LineMode;
32
+ /** tsv: the column names, comma separated. */
33
+ columns: string;
34
+ /** A plain dotted path per result field; a mapping that is more than a path is kept as it is and listed in `complex`. */
35
+ fields: Record<FieldKey, string>;
36
+ complex: FieldKey[];
37
+ timeoutMs: string;
38
+ maxOutputBytes: string;
39
+ /** The purposes: a general search engine, and/or the platforms whose backend chain it may sit in. */
40
+ engine: boolean;
41
+ platforms: string[];
42
+ /** Empty = the default (0.5). */
43
+ confidence: string;
44
+ packageNote: string;
45
+ /** The probe: the help command (space separated) and the fragments its output must contain. */
46
+ helpArgs: string;
47
+ mustContain: string[];
48
+ }
49
+ /** The spec a new entry starts from: a JSON-printing tool mapped url / title / snippet. The form fills the command in. */
50
+ export declare function newSpec(): Json;
51
+ /** The example of the dialog: `echo`, whose whole output is the result (no field mapping), a way to see the pieces work without a real tool. */
52
+ export declare function echoSpec(): Json;
53
+ /** The form fields of a spec (plain or not): everything the dialog shows, as text. */
54
+ export declare function specToForm(id: string, raw: unknown): CliForm;
55
+ /** The command words the argv templates of a spec use, in order, without repeats: what `allowedSubcommands` must list. */
56
+ export declare function derivedSubcommands(spec: Json): string[];
57
+ /**
58
+ * The spec the form describes, built on `base` (the entry as it was: every key the form has no control for is kept). Nothing is
59
+ * validated here; a value that is not what its box wants is written as typed so `validateCliAdapterSpec` names it.
60
+ */
61
+ export declare function formToSpec(form: CliForm, base?: Json): Json;
62
+ /** The names of the dialog's fields that an error message can be about. */
63
+ export type ErrorField = 'id' | 'bin' | 'argv' | 'format' | 'itemsPath' | 'lines' | 'fields' | FieldKey | 'timeoutMs' | 'maxOutputBytes' | 'platforms' | 'engine' | 'confidence' | 'packageNote' | 'probe' | 'general';
64
+ /** Sort the validator's messages (`cliAdapters.<id>.<path>: ...`) to the dialog field they are about. */
65
+ export declare function errorsByField(id: string, errors: readonly string[]): Partial<Record<ErrorField, string[]>>;
66
+ export interface CliCheck {
67
+ spec: Json;
68
+ /** The validator's messages (empty = valid). */
69
+ errors: string[];
70
+ byField: Partial<Record<ErrorField, string[]>>;
71
+ ok: boolean;
72
+ }
73
+ /** Build the spec of a form and validate it the way the server does; `taken` are the ids of the other entries (a new id may not repeat one). */
74
+ export declare function checkForm(form: CliForm, base: Json, taken?: readonly string[]): CliCheck;
75
+ /** Validate a spec (the JSON view): the server's function, plus the one rule only the editor has (an id is not used twice). */
76
+ export declare function checkSpec(id: string, spec: Json, taken?: readonly string[]): CliCheck;
77
+ /** The confidence the entry has: its own, else the default. */
78
+ export declare const confidenceOfForm: (form: CliForm) => number;
79
+ export { WHOLE_OUTPUT_DEFAULT_CHARS };
80
+ /** The JSON text of a spec as the dialog's raw box prints it. */
81
+ export declare const specText: (spec: Json) => string;
82
+ /** The spec a raw JSON text holds, or the reason it is not one. */
83
+ export declare function parseSpecText(text: string): {
84
+ spec: Json;
85
+ } | {
86
+ error: string;
87
+ };
88
+ /** The `cliAdapters` object of the staged text (empty text = no entries); undefined when it is not an object. */
89
+ export declare function adaptersOf(text: string): Json | undefined;
90
+ /**
91
+ * The `cliAdapters` text with entry `id` set to `spec` (a new key goes last), or removed when `spec` is undefined. The other
92
+ * entries are kept as they were. The object with no entries comes back as the empty text, which the form model stores as "not set".
93
+ * Undefined when the current text is not an object (the raw JSON box has to be fixed first).
94
+ */
95
+ export declare function withAdapter(text: string, id: string, spec: Json | undefined): string | undefined;
96
+ /** A free id for a copy or a new entry: `base`, `base-2`, `base-3`, ... */
97
+ export declare function freeId(base: string, taken: readonly string[]): string;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The comment printed in front of every key of the text view ("Advanced: text mode"), in the language of the card: what the
3
+ * setting is for, its allowed values or range, its default, and the risk when there is one. Comment lines start with `#`, so
4
+ * the text stays valid YAML and a round trip never reads a comment as data. Pure (it imports only config-groups.ts): the text view and the
5
+ * tests read it, and the client bundle includes it. Nothing here names a secret value: keys are only ever referenced by name.
6
+ * @module web-search-pro/client/field-docs
7
+ */
8
+ export type DocLang = 'en' | 'zh';
9
+ /** The doc of a config field in a language; undefined only for a field the card does not know. */
10
+ export declare function fieldDoc(field: string, lang?: DocLang | string): string | undefined;
11
+ /** The docs of the groups of keys and the header of the text view. */
12
+ export declare function textViewDocs(lang?: DocLang | string): {
13
+ header: readonly string[];
14
+ group: Readonly<Record<string, string>>;
15
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Which dictionary entry names a field, which fields carry a `?` text of their own, and the facts about the sources the
3
+ * card lists. Pure data (no imports): the rows, the text view and the tests all read it.
4
+ * @module web-search-pro/client/field-keys
5
+ */
6
+ import { type ConfigGroupId } from '../config-groups.ts';
7
+ export declare function labelKey(field: string): string;
8
+ /** The fields whose dictionary has a `<key>Help` text (a longer explanation behind the `?`). */
9
+ export declare const WITH_HELP: ReadonlySet<string>;
10
+ /** `?` text applies to the generic budget keys too. */
11
+ export declare const hasHelp: (field: string) => boolean;
12
+ /** Dictionary key of the sentence saying why a start-up-only field needs a plugin restart (restart.ts lists the fields). */
13
+ export declare function restartWhyKey(field: string): string;
14
+ export type SourceTier = 'paid' | 'free-quota' | 'anonymous';
15
+ /** One source the "Sources" list shows and its edit dialog is made of. */
16
+ export interface SourceDef {
17
+ id: string;
18
+ name: string;
19
+ tier: SourceTier;
20
+ /** "常用": the plugin's recommended source (pinned to the registry descriptors by a test). */
21
+ common?: boolean;
22
+ /** The write-only key of the source (`CredentialId`), and the field naming the credential / variable it is stored under. */
23
+ credential?: string;
24
+ envField?: string;
25
+ defaultEnv?: string;
26
+ baseUrlField?: string;
27
+ /** Other fields the dialog holds, in order. */
28
+ extra?: readonly string[];
29
+ /** The request budget of the source (`sources.budget.<id>.total|daily`). */
30
+ budget?: boolean;
31
+ }
32
+ export declare const SOURCE_DEFS: readonly SourceDef[];
33
+ /** Fields of a source dialog in display order (the key itself is a credential, not a field). */
34
+ export declare function sourceFields(def: SourceDef): string[];
35
+ /** Fields shown as JSON objects, each in its own dialog: the field, the group it sits in. */
36
+ export declare const JSON_FIELDS: readonly {
37
+ field: string;
38
+ group: 'judge' | 'runtime' | 'platform' | 'advanced';
39
+ }[];
40
+ /** Group of the text view of any field: the group of its top-level key (see config-groups.ts, the one list of the layout). */
41
+ export declare function textGroupOf(field: string): ConfigGroupId;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Rows for the configuration fields the groups edit, wired to the card's staged form state.
3
+ *
4
+ * One component per control kind (switch, select, text, number, list of ids). Each is the single entry of its field: it renders
5
+ * `data-wsp-field="<field>"`, which test/settings-card-render.test.ts counts, and it reads the label, the one-line hint and the
6
+ * optional `?` text from the dictionary by the field's name (`<key>`, `<key>Hint`, `<key>Help`, see field-keys.ts).
7
+ * @module web-search-pro/client/field-rows
8
+ */
9
+ import type { SettingsCardProps } from './index.ts';
10
+ import type { CardFieldState, WebSearchCardState } from './form.ts';
11
+ import { fill } from './fill.ts';
12
+ import { type RowLabels, type SelectOption } from './ui-kit.tsx';
13
+ export type Card = SettingsCardProps;
14
+ export type Translator = Card['t'];
15
+ export type LabelKey = Parameters<Translator>[0];
16
+ export { fill };
17
+ export declare function rowLabels(t: Translator): RowLabels;
18
+ /** The id of a field's control, tied to its label. */
19
+ export declare const controlId: (field: string) => string;
20
+ /** The units a number field is written with. */
21
+ declare const UNIT_KEYS: {
22
+ readonly ms: "unitMs";
23
+ readonly sec: "unitSeconds";
24
+ readonly chars: "unitChars";
25
+ readonly count: "unitCount";
26
+ readonly tokens: "unitTokens";
27
+ readonly days: "unitDays";
28
+ readonly rounds: "unitCount";
29
+ };
30
+ export type Unit = keyof typeof UNIT_KEYS;
31
+ export interface FieldProps {
32
+ card: Card;
33
+ /** The setting field this row is the entry of. */
34
+ field: string;
35
+ /** Replaces the dictionary hint. */
36
+ hint?: string;
37
+ placeholder?: string;
38
+ /** Replaces the dictionary label. */
39
+ label?: string;
40
+ /** A short warning badge beside the label. */
41
+ risk?: string;
42
+ /** Hide the "overridden" badge and reset: for fields whose "default" is a computed one. */
43
+ code?: boolean;
44
+ }
45
+ /** How many of these fields carry an override: the number a group's badge shows. */
46
+ export declare function useOverriddenCount(card: Card, fields: readonly string[]): number;
47
+ /** The staged state of a field. */
48
+ export declare const stateOf: (snapshot: WebSearchCardState, field: string) => CardFieldState | undefined;
49
+ export declare function useField(card: Card, field: string): {
50
+ state: CardFieldState;
51
+ disabled: boolean;
52
+ edit: (text: string) => void;
53
+ reset: () => void;
54
+ };
55
+ /** A boolean field as a switch. */
56
+ export declare function SwitchRow(props: FieldProps): import("react").JSX.Element;
57
+ /** An enumerated field as a drop-down. */
58
+ export declare function SelectRow(props: FieldProps & {
59
+ options: readonly SelectOption[];
60
+ }): import("react").JSX.Element;
61
+ /** A free-text field. */
62
+ export declare function TextRow(props: FieldProps): import("react").JSX.Element;
63
+ /** A number field with its unit written after the input. */
64
+ export declare function NumberRow(props: FieldProps & {
65
+ unit?: Unit;
66
+ }): import("react").JSX.Element;
67
+ declare const parseList: (text: string) => string[];
68
+ /** A comma-separated list (engine ids, domains) as removable chips with an add box. */
69
+ export declare function ListRow(props: FieldProps): import("react").JSX.Element;
70
+ export { parseList };
@@ -0,0 +1,2 @@
1
+ /** Fill `{name}` placeholders of a dictionary entry. */
2
+ export declare const fill: (text: string, values: Record<string, string | number>) => string;