@eddyskywalker/dsh-chatgpt-subscription 0.36.2 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +23 -3
  3. package/lib/client.js +340 -47
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +3043 -40
  6. package/lib/types/client/common/ComposerQuotaBadge.d.ts +7 -0
  7. package/lib/types/client/common/ComposerQuotaBadge.d.ts.map +1 -1
  8. package/lib/types/client/locales-ru/opendesign.d.ts.map +1 -1
  9. package/lib/types/client/locales-ru/progress-updates.d.ts.map +1 -1
  10. package/lib/types/client/locales.d.ts +4 -4
  11. package/lib/types/client/opendesign/OpenDesignComposerQuota.d.ts +6 -0
  12. package/lib/types/client/opendesign/OpenDesignComposerQuota.d.ts.map +1 -1
  13. package/lib/types/client/opendesign/OpenDesignSection.d.ts.map +1 -1
  14. package/lib/types/client/opendesign/locales.d.ts +54 -0
  15. package/lib/types/client/opendesign/locales.d.ts.map +1 -1
  16. package/lib/types/client/opendesign/styles.d.ts +5 -0
  17. package/lib/types/client/opendesign/styles.d.ts.map +1 -1
  18. package/lib/types/client/progress-updates/locales.d.ts +17 -2
  19. package/lib/types/client/progress-updates/locales.d.ts.map +1 -1
  20. package/lib/types/client/progress-updates/settings-binding.d.ts +13 -3
  21. package/lib/types/client/progress-updates/settings-binding.d.ts.map +1 -1
  22. package/lib/types/client/progress-updates/settings-section.d.ts +5 -5
  23. package/lib/types/client/progress-updates/settings-section.d.ts.map +1 -1
  24. package/lib/types/client/progress-updates/styles.d.ts.map +1 -1
  25. package/lib/types/host/opendesign/client.d.ts +103 -0
  26. package/lib/types/host/opendesign/client.d.ts.map +1 -1
  27. package/lib/types/host/opendesign/routes.d.ts.map +1 -1
  28. package/lib/types/host/opendesign/types.d.ts +31 -0
  29. package/lib/types/host/opendesign/types.d.ts.map +1 -1
  30. package/lib/types/host/progress-updates/index.d.ts +5 -0
  31. package/lib/types/host/progress-updates/index.d.ts.map +1 -1
  32. package/lib/types/host/progress-updates/prompt.d.ts +37 -3
  33. package/lib/types/host/progress-updates/prompt.d.ts.map +1 -1
  34. package/lib/types/host/progress-updates/tool.d.ts.map +1 -1
  35. package/lib/types/host/proxy-manager.d.ts +63 -1
  36. package/lib/types/host/proxy-manager.d.ts.map +1 -1
  37. package/lib/types/host/widget-board/line-contracts.d.ts +192 -0
  38. package/lib/types/host/widget-board/line-contracts.d.ts.map +1 -0
  39. package/lib/types/host/widget-board/line-quota.d.ts +284 -0
  40. package/lib/types/host/widget-board/line-quota.d.ts.map +1 -0
  41. package/lib/types/host/widget-board/line-registry.d.ts +402 -0
  42. package/lib/types/host/widget-board/line-registry.d.ts.map +1 -0
  43. package/lib/types/host/widget-board/provider.d.ts +140 -0
  44. package/lib/types/host/widget-board/provider.d.ts.map +1 -0
  45. package/lib/types/index.d.ts +10 -0
  46. package/lib/types/index.d.ts.map +1 -1
  47. package/lib/types/shared/opendesign-contracts.d.ts +47 -0
  48. package/lib/types/shared/opendesign-contracts.d.ts.map +1 -1
  49. package/package.json +2 -1
  50. package/widgets/line-flip/index.html +58 -0
  51. package/widgets/line-flip/main.js +1102 -0
  52. package/widgets/line-flip/style.css +729 -0
  53. package/widgets/line-flip/widget.json +555 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-quota.d.ts","sourceRoot":"","sources":["../../../../src/host/widget-board/line-quota.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,EAEV,aAAa,EAEb,cAAc,EACf,MAAM,qBAAqB,CAAA;AAE5B,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,6EAA6E;IAC7E,KAAK,EAAE,aAAa,GAAG,IAAI,CAAA;IAC3B,gEAAgE;IAChE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,6EAA6E;IAC7E,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAA;IACxB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAiZD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAmDnE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CA6BtE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAkCzE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAgCzE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAmCzE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAwBpE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAsB3E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAmCtE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAsCnE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CA4BvE;AAsED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CA+BxE;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,uBAAuB;IACtC,uEAAuE;IACvE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,uEAAuE;IACvE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB;;;;;OAKG;IACH,OAAO,EAAE,cAAc,EAAE,CAAA;CAC1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,OAAO,GAAG,uBAAuB,GAAG,IAAI,CAY1F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,GAAG,IAAI,CAmBzF;AA0CD;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,cAAc,CAAC,CAYhG,CAAA"}
@@ -0,0 +1,402 @@
1
+ /**
2
+ * The line registry: one entry per subscription line, and the two halves of a
3
+ * card answered from different authorities.
4
+ *
5
+ * WHY THE SPLIT
6
+ *
7
+ * - ACCOUNTS travel through the pools, in process. Every line's pool already
8
+ * speaks the same three methods (listAccounts / setPrimary / setStrategy) and
9
+ * hands back the same row DTO, so ONE generic adapter covers all of them — no
10
+ * HTTP, no per-line code, and no second implementation of eligibility,
11
+ * cooldowns or the rotation strategy. The line → pool mapping is injected by
12
+ * src/index.ts, where every pool is in scope; nothing here imports a concrete
13
+ * pool class, so a new line is a wiring change, not a change to this module.
14
+ *
15
+ * - QUOTA travels over LOOPBACK HTTP, through the line's own status route. Each
16
+ * line's route already normalizes its provider payload into its own DTO and
17
+ * owns the cache, the refresh flight and the error reporting for it. Reading
18
+ * the provider directly from here would be a second reader of the same
19
+ * upstream, free to drift from the one the settings card shows. The loopback
20
+ * call needs no credential: these are the very same GET /status requests this
21
+ * plugin's own settings page makes.
22
+ *
23
+ * A read is therefore two independent tasks in parallel, and NEITHER can take
24
+ * the other down: a pool file that will not decrypt still leaves the card with
25
+ * its quota, and a line whose route is unreachable still leaves it with its
26
+ * accounts.
27
+ *
28
+ * - PER-ACCOUNT QUOTA is the third, OPTIONAL half, and the one neither of the
29
+ * other two can answer: a pool row carries a snapshot only for the account
30
+ * that was actually read, so on a two-account line the second row has nothing
31
+ * to draw. A line that opts in hands over a reader
32
+ * ({@link LINE_ACCOUNT_QUOTA_READERS}) which — given ONE account's credential —
33
+ * asks that line's own client for that account's own numbers. The reader is
34
+ * INJECTED, never imported: each one needs a concrete line client, and this
35
+ * module imports no line at all. A line with no reader behaves exactly as
36
+ * before, which is why every line that does not opt in is untouched.
37
+ *
38
+ * The opt-in half is bounded FOUR ways, because it is the only part of a read
39
+ * that spends upstream requests per ACCOUNT: one budget for one account
40
+ * ({@link LINE_ACCOUNT_QUOTA_TIMEOUT_MS}), ONE budget for the whole per-account
41
+ * stage ({@link LINE_ACCOUNT_QUOTA_WHOLE_BUDGET_MS}), a cache per (line,
42
+ * account) so a card polling every 60 s does not become a poll of the upstream
43
+ * ({@link LINE_ACCOUNT_QUOTA_CACHE_MS} — with a much shorter TTL for a failed
44
+ * entry, {@link LINE_ACCOUNT_QUOTA_FAILURE_CACHE_MS}, so a recovered account
45
+ * comes back on the next poll), a small concurrency gate
46
+ * ({@link LINE_ACCOUNT_QUOTA_CONCURRENCY}), and a cap on how many accounts one
47
+ * read spends a request on at all ({@link LINE_ACCOUNT_QUOTA_MAX_ACCOUNTS}).
48
+ * Every failure is absorbed on the ONE row it belongs to: a reader that
49
+ * throws, times out or answers null leaves that row unread and touches nothing
50
+ * else — no other row, no other line, and never the card's error field.
51
+ *
52
+ * EVERY failure is bounded, and the bound does NOT grow with the account count:
53
+ * the two halves a card reads are bounded by the HTTP budget (5 s,
54
+ * {@link LINE_HTTP_TIMEOUT_MS}), and the per-account stage is bounded by ITS OWN
55
+ * budget (6 s, {@link LINE_ACCOUNT_QUOTA_WHOLE_BUDGET_MS}) rather than by
56
+ * ceil(accounts / concurrency) × 5 s — so six accounts whose readers all hang
57
+ * answer in 6 s instead of 15 s, and a board of such cards is not a board that
58
+ * hangs. A row the whole stage did not reach is not a failure: it stays blank
59
+ * and is tried again on the next read, because the cache is per account.
60
+ */
61
+ import type { AccountRotationStrategy, PoolAccountSummaryDto } from '../../shared/account-pool-contracts.ts';
62
+ import type { LineCardData } from './line-contracts.ts';
63
+ import { type LineAccountQuotaReading, type LineQuotaFacts } from './line-quota.ts';
64
+ /**
65
+ * How long one line's HTTP read may take, in milliseconds.
66
+ *
67
+ * A board data source is read while a card paints, so this is a ceiling rather
68
+ * than a target: every one of these routes answers from a local cache in
69
+ * milliseconds, and five seconds is the point at which "slow" has already
70
+ * become "broken" for the user watching an empty card.
71
+ */
72
+ export declare const LINE_HTTP_TIMEOUT_MS = 5000;
73
+ /**
74
+ * How long ONE account's extra quota read may take, in milliseconds.
75
+ *
76
+ * Equal to the card's own HTTP budget rather than shorter. It was three seconds
77
+ * first, on the theory that a warm route answers in milliseconds; MEASURED
78
+ * against a live Qoder endpoint, the same read took 107 ms, 573 ms, 1254 ms —
79
+ * and twice over three seconds on a cold process. With the failure cache below,
80
+ * a budget that tight converts "the first card after a restart" into "a blank
81
+ * row for the next quarter of a minute", which is a worse answer than waiting
82
+ * two extra seconds once. Five seconds also cannot lengthen a card: the rows are
83
+ * read two at a time, so a two-account line still answers inside one budget.
84
+ *
85
+ * The same budget covers the credential lookup and the upstream call together —
86
+ * it is one deadline for one row, not one per step.
87
+ */
88
+ export declare const LINE_ACCOUNT_QUOTA_TIMEOUT_MS = 5000;
89
+ /**
90
+ * How long one SUCCESSFUL (line, account) reading is reused, in milliseconds.
91
+ *
92
+ * The board re-reads a card every 60 seconds, and there are two rows on the
93
+ * lines this exists for. Without a cache every poll would be two upstream
94
+ * requests per account — the quota endpoint is a personal, undocumented one, and
95
+ * hammering it on a timer is how an account gets rate-limited by its own card.
96
+ * Sixty seconds is therefore a FLOOR: a reading is never reused for less.
97
+ */
98
+ export declare const LINE_ACCOUNT_QUOTA_CACHE_MS = 60000;
99
+ /**
100
+ * How long a FAILED (line, account) reading is reused, in milliseconds.
101
+ *
102
+ * Deliberately NOT the same TTL as a success, because the two entries are
103
+ * remembered for opposite reasons:
104
+ *
105
+ * - a success is cached to stop the board from polling the upstream, so its TTL
106
+ * is the poll interval;
107
+ * - a failure is cached to stop a broken account from being retried on every
108
+ * tick — but every minute it lasts is also a minute of a row that HAS numbers
109
+ * available and is not showing them (a transient timeout, an upstream blip, a
110
+ * credential that just got renewed). Fifteen seconds bounds that cost: a
111
+ * failure is retried about four times a minute, which is far below anything
112
+ * the upstream would notice, and a recovered account is back on the card on
113
+ * the very next poll instead of the one after it.
114
+ *
115
+ * Both entries are remembered rather than dropped: forgetting a failure would
116
+ * turn one dead account into one upstream request per card read.
117
+ */
118
+ export declare const LINE_ACCOUNT_QUOTA_FAILURE_CACHE_MS = 15000;
119
+ /**
120
+ * How many per-account quota reads one registry may have in flight at once.
121
+ *
122
+ * Two, so a single card read (one per row) is sequential at worst on the lines
123
+ * that exist today, while a board showing two cards of the same line still
124
+ * cannot fan out into a burst of upstream requests.
125
+ */
126
+ export declare const LINE_ACCOUNT_QUOTA_CONCURRENCY = 2;
127
+ /**
128
+ * How long the WHOLE per-account stage of ONE card read may take, in
129
+ * milliseconds.
130
+ *
131
+ * Not about one account: this is the ceiling on everything a card waits for while
132
+ * it asks each row's own upstream. The per-account budget above bounds one ROW,
133
+ * and on its own it composes badly — rows are read two at a time, so N accounts
134
+ * cost ceil(N / 2) × 5 s in the worst case, which is 15 s on six accounts and
135
+ * grows without limit. That is the number this constant removes: six accounts
136
+ * whose readers all hang now answer in six seconds rather than fifteen, and the
137
+ * same six seconds covers sixty accounts.
138
+ *
139
+ * Why 6 s and not 5: one account must still be able to spend its FULL
140
+ * per-account budget — the credential lookup and the upstream call share that
141
+ * deadline, and a cold upstream has been measured over three seconds twice — so a
142
+ * stage shorter than the row budget would silently turn every cold first read
143
+ * into a blank row. The extra second is what lets the first pair of a
144
+ * two-account line finish, failure path included, before the stage closes.
145
+ *
146
+ * Running out is NOT an error. Rows that answered before the deadline keep their
147
+ * numbers; rows that did not stay UNREAD — `usedPercent: null`, no window list,
148
+ * and no entry in the card's `error` field. The next read (the board's 60 s poll,
149
+ * or a manual refresh) tries them again, which works because the cache is keyed
150
+ * per account and a row that never answered was never cached.
151
+ */
152
+ export declare const LINE_ACCOUNT_QUOTA_WHOLE_BUDGET_MS = 6000;
153
+ /**
154
+ * How many accounts ONE read may spend a per-account request on.
155
+ *
156
+ * The stage budget above bounds the TIME; this bounds the WORK. A line with three
157
+ * hundred pooled accounts would otherwise open a hundred and fifty credential
158
+ * lookups and upstream quota requests per card read — each one billed to a
159
+ * personal, undocumented endpoint — and the rows past the first few could never be
160
+ * reached before the budget expired anyway. Reading eight and leaving the rest
161
+ * unread is the honest version of that: the extra rows stay blank instead of
162
+ * queueing behind a deadline they cannot meet.
163
+ *
164
+ * WHICH eight, when there are more: primary first, then most recently used
165
+ * ({@link PoolAccountSummaryDto.lastUsedAt} descending, pool order on ties), so
166
+ * the cap spends the card's requests on the rows a reader is most likely looking
167
+ * at. A rotation moves that window on the next read.
168
+ */
169
+ export declare const LINE_ACCOUNT_QUOTA_MAX_ACCOUNTS = 8;
170
+ /**
171
+ * One line, as this registry reads it.
172
+ *
173
+ * A definition carries no service: the pool arrives through the injected
174
+ * mapping and the routes are addressed by path, which is what lets one module
175
+ * describe eleven lines without importing eleven implementations.
176
+ */
177
+ export interface LineDefinition {
178
+ /** Line id a card names, e.g. `codex`. Also the pool mapping's key. */
179
+ id: string;
180
+ /** Display name, e.g. `ChatGPT`. */
181
+ label: string;
182
+ /** The line's own status route, e.g. `/claude/api/status`. */
183
+ statusPath: string;
184
+ /**
185
+ * The line's own quota-refresh route, POSTed before the status route is read
186
+ * again. Null for a line whose status read is already authoritative.
187
+ */
188
+ refreshPath: string | null;
189
+ /** The line's payload → shape C's quota half. */
190
+ normalize(status: unknown): LineQuotaFacts;
191
+ }
192
+ /**
193
+ * Every line this plugin can serve a card for.
194
+ *
195
+ * The routes are the lines' own, verbatim: this module is not allowed to invent
196
+ * a prefix, because a prefix is what a line owns.
197
+ */
198
+ export declare const LINE_DEFINITIONS: readonly LineDefinition[];
199
+ /**
200
+ * What one line's client is handed to read ONE account's quota.
201
+ *
202
+ * @see LineAccountQuotaClient for why this is an object rather than a bare
203
+ * `fetch`: the account id is not bookkeeping, it is half of the question.
204
+ */
205
+ export interface LineAccountQuotaContext {
206
+ /**
207
+ * The pool account this reading is for.
208
+ *
209
+ * Load-bearing, not decoration: a line remembers a quota snapshot against the
210
+ * account it was read for, so a reader that cannot name the account has its
211
+ * snapshot stored under no key at all — and the NEXT account's read is then
212
+ * answered from the previous account's cache with the previous account's
213
+ * numbers. That is exactly the failure this whole hook exists to fix.
214
+ */
215
+ accountId: string;
216
+ /**
217
+ * The HTTP client for this one read.
218
+ *
219
+ * It already carries the row's deadline as its `signal`, so a client that
220
+ * honours `signal` is cancelled by the budget rather than merely abandoned.
221
+ * The reader must not replace it with a longer-lived one.
222
+ */
223
+ fetchFn: typeof fetch;
224
+ }
225
+ /**
226
+ * One line's quota client, as the composition hands it over.
227
+ *
228
+ * The payload is the line's OWN DTO, `unknown` here on purpose: this module
229
+ * reads no line's types, and the pure mapping from that DTO to
230
+ * {@link LineAccountQuotaReading} lives beside the normalizers in
231
+ * `line-quota.ts` ({@link LINE_ACCOUNT_QUOTA_READERS} names which one applies).
232
+ *
233
+ * @param credentials - This account's credential, from the pool kernel.
234
+ * @param context - Which account, and the client to read it with.
235
+ * @returns The line's raw quota payload; null when the line measured nothing.
236
+ */
237
+ export type LineAccountQuotaClient = (credentials: unknown, context: {
238
+ fetchFn: typeof fetch;
239
+ accountId: string;
240
+ }) => Promise<unknown>;
241
+ /**
242
+ * One line's per-account quota reader: credentials in, the row's two facts out.
243
+ *
244
+ * @param credentials - This account's credential, from the pool kernel. Never a
245
+ * credential this module chose a different account for: the row and the
246
+ * reading must describe the same account.
247
+ * @param context - Which account, and the client to read it with.
248
+ * @returns The reading, or null when this account's quota was not measurable.
249
+ */
250
+ export type LineAccountQuotaReader = (credentials: unknown, context: LineAccountQuotaContext) => Promise<LineAccountQuotaReading | null>;
251
+ /**
252
+ * A line's reader, once its client is known.
253
+ *
254
+ * A factory rather than a plain function so the assembly of "which bucket /
255
+ * which window" stays HERE while "how to reach that line's upstream" stays in
256
+ * the composition: {@link createAccountQuotaReaders} hands the client in, and a
257
+ * line whose client was not injected simply produces no reader at all.
258
+ */
259
+ export type LineAccountQuotaReaderFactory = (client: LineAccountQuotaClient) => LineAccountQuotaReader;
260
+ /**
261
+ * THE per-account quota hook table: line id → how that line's readings are made.
262
+ *
263
+ * Keying it by line id is the whole point: a card names a line, a row names an
264
+ * account, and a line with no entry here keeps EXACTLY the behaviour it had
265
+ * before this table existed. That is not a fallback nobody exercised — it is the
266
+ * default for nine of the eleven lines.
267
+ *
268
+ * Nothing in this table imports a line. Each entry needs that line's client and
269
+ * receives it ({@link LineAccountQuotaClient}); a future line adds one entry
270
+ * here plus one injected client, and no other module has to learn about it.
271
+ *
272
+ * What justified the two entries:
273
+ *
274
+ * - `qoder` — the line's `quota/usage` snapshot states absolute buckets, not a
275
+ * percentage; {@link qoderAccountQuotaReading} derives a share only when a
276
+ * bucket bounded it (total > 0) AND stated what was used. No bounded bucket,
277
+ * no bar.
278
+ * - `minimax-code` — the Token Plan states a 5-hour (`interval`) and a weekly
279
+ * window; the row draws the 5-hour one, because that is the tightest limit the
280
+ * plan has ({@link minimaxAccountQuotaReading}). The weekly window is never
281
+ * substituted for it.
282
+ */
283
+ export declare const LINE_ACCOUNT_QUOTA_READERS: Readonly<Record<string, LineAccountQuotaReaderFactory | undefined>>;
284
+ /**
285
+ * The readers in force, built from the clients the composition injected.
286
+ *
287
+ * A line whose client was not injected gets NO reader, which is what keeps the
288
+ * hook optional in practice and not merely on paper: a composition that hands
289
+ * over none of these reads every card exactly as it did before.
290
+ *
291
+ * @param clients - Line id → that line's quota client. Omitted or partial is the
292
+ * normal case, not an error.
293
+ * @returns Line id → the reader for it; lines without both halves are absent.
294
+ */
295
+ export declare function createAccountQuotaReaders(clients: Readonly<Record<string, LineAccountQuotaClient | undefined>> | undefined): Readonly<Record<string, LineAccountQuotaReader | undefined>>;
296
+ /**
297
+ * The part of a pool this registry drives.
298
+ *
299
+ * All three methods are the shared pool kernel's own, which is why the pool
300
+ * mapping can be one generic adapter instead of eleven: the row DTO is shared
301
+ * and the three calls are shared.
302
+ */
303
+ export interface LineAccountSource {
304
+ listAccounts(): Promise<PoolAccountSummaryDto[]>;
305
+ setPrimary(accountId: string): Promise<void>;
306
+ setStrategy(strategy: AccountRotationStrategy): Promise<void>;
307
+ /**
308
+ * The whole pool document, for the two facts a list of rows cannot state:
309
+ * the ACTIVE account (a pool may have none yet) and the rotation strategy.
310
+ *
311
+ * Optional because not every line exposes it; when it is absent the strategy
312
+ * is reported as the pool's own default and the active account is the primary
313
+ * row, which is what a sequential pool resolves to anyway.
314
+ */
315
+ read?(): Promise<unknown>;
316
+ /**
317
+ * One NAMED account's credential, renewed if it is about to expire.
318
+ *
319
+ * This is the shared pool kernel's own `getFreshCredential`, narrowed to what
320
+ * a quota read needs. It is the right method rather than the routing one for
321
+ * the reason the kernel already documents: reading a quota is not serving a
322
+ * request, so it addresses an account by id, ignores cooldowns and the pin,
323
+ * and writes no rotation bookkeeping — switching accounts, spending the
324
+ * rotation state or promoting a row is explicitly NOT something a card may do
325
+ * behind the user's back.
326
+ *
327
+ * Optional: absent on a source that cannot hand a credential over, and a line
328
+ * whose source does not have it simply gets no per-account reading.
329
+ *
330
+ * A refresh here is the pool's own single-flight renewal, and it is the one
331
+ * write this hook can cause — the same write the settings card's quota read
332
+ * causes on the same method. This module writes no credential file of its own.
333
+ */
334
+ getFreshCredential?(accountId: string, fetchFn?: typeof fetch): Promise<unknown>;
335
+ }
336
+ /** What {@link createLineRegistry} is handed. */
337
+ export interface LineRegistryOptions {
338
+ /** This host's own origin, resolved lazily so a not-yet-bound port is not fatal at load. */
339
+ origin(): string;
340
+ /** Line id → the pool to drive. A line with no entry is reported uninstalled. */
341
+ pools: Readonly<Record<string, LineAccountSource | undefined>>;
342
+ /** Test seam: the HTTP client. Defaults to the global fetch. */
343
+ fetchFn?: typeof fetch;
344
+ /** Test seam: the whole-read budget in milliseconds. */
345
+ timeoutMs?: number;
346
+ /**
347
+ * Line id → that line's quota client, for the lines that opt in to a
348
+ * per-account reading.
349
+ *
350
+ * Injected rather than imported so this module stays free of every line's
351
+ * implementation (and of the process-wide caches those modules keep): the
352
+ * composition already holds all of them, because it is where the pools are
353
+ * wired. A line with no client here — which is nine of eleven today — keeps
354
+ * the behaviour it had before this option existed.
355
+ */
356
+ accountQuotaClients?: Readonly<Record<string, LineAccountQuotaClient | undefined>>;
357
+ /** Test seam: how long one SUCCESSFUL (line, account) reading is reused. */
358
+ accountQuotaCacheMs?: number;
359
+ /** Test seam: how long a FAILED (line, account) reading is reused. */
360
+ accountQuotaFailureCacheMs?: number;
361
+ /** Test seam: one account's own read budget in milliseconds. */
362
+ accountQuotaTimeoutMs?: number;
363
+ /**
364
+ * Test seam: the budget for the WHOLE per-account stage in milliseconds,
365
+ * which is what bounds the card rather than any one row.
366
+ */
367
+ accountQuotaWholeBudgetMs?: number;
368
+ /** Test seam: how many accounts one read may spend a request on. */
369
+ accountQuotaMaxAccounts?: number;
370
+ /** Test seam: the lines to serve. Defaults to {@link LINE_DEFINITIONS}. */
371
+ definitions?: readonly LineDefinition[];
372
+ }
373
+ /** The registry a card reads through. */
374
+ export interface LineRegistry {
375
+ /** Every line this registry serves, in display order. */
376
+ readonly definitions: readonly LineDefinition[];
377
+ /** The ids {@link LineRegistry.read} accepts. */
378
+ ids(): string[];
379
+ /** Read one line's card. Throws for an unknown line. */
380
+ read(line: string, signal?: AbortSignal): Promise<LineCardData>;
381
+ /** POST the line's own refresh route, then read its card. */
382
+ refresh(line: string, signal?: AbortSignal): Promise<LineCardData>;
383
+ /** Pin one of the line's pooled accounts, then read its card. */
384
+ switchAccount(line: string, accountId: string, signal?: AbortSignal): Promise<LineCardData>;
385
+ /** Change the line's rotation strategy, then read its card. */
386
+ changeStrategy(line: string, strategy: string, signal?: AbortSignal): Promise<LineCardData>;
387
+ }
388
+ /**
389
+ * Build a registry over the injected line → pool mapping.
390
+ *
391
+ * @param options - The mapping, the origin and the seams.
392
+ * @returns The registry.
393
+ */
394
+ export declare function createLineRegistry(options: LineRegistryOptions): LineRegistry;
395
+ /**
396
+ * The line a card names, from its props.
397
+ *
398
+ * @param props - The card's props.
399
+ * @returns The line id.
400
+ */
401
+ export declare function lineOfProps(props: unknown): string;
402
+ //# sourceMappingURL=line-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-registry.d.ts","sourceRoot":"","sources":["../../../../src/host/widget-board/line-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,140 @@
1
+ import { type LineAccountQuotaClient, type LineAccountSource } from './line-registry.ts';
2
+ /** The card a data source or a capability is called for. */
3
+ export interface WidgetBoardInstance {
4
+ id: string;
5
+ widget: string;
6
+ props: Record<string, unknown>;
7
+ }
8
+ /** A data source registration, as this provider fills it in. */
9
+ export interface WidgetBoardDataSourceRegistration {
10
+ apiVersion: number;
11
+ provider: string;
12
+ id: string;
13
+ read(instance: WidgetBoardInstance): unknown | Promise<unknown>;
14
+ }
15
+ /** A capability registration, as this provider fills it in. */
16
+ export interface WidgetBoardCapabilityRegistration {
17
+ apiVersion: number;
18
+ provider: string;
19
+ id: string;
20
+ title?: {
21
+ zh: string;
22
+ en: string;
23
+ };
24
+ description?: {
25
+ zh: string;
26
+ en: string;
27
+ };
28
+ input?: Record<string, unknown>;
29
+ output?: Record<string, unknown>;
30
+ call(instance: WidgetBoardInstance, args: unknown, signal: AbortSignal): unknown | Promise<unknown>;
31
+ }
32
+ /** The lifecycle handle one widget-type registration answers with. */
33
+ export interface WidgetBoardHandle {
34
+ readonly provider: string;
35
+ readonly widgets: readonly string[];
36
+ register(registrations?: {
37
+ dataSources?: WidgetBoardDataSourceRegistration[];
38
+ capabilities?: WidgetBoardCapabilityRegistration[];
39
+ }): () => void;
40
+ dispose(): Promise<void>;
41
+ }
42
+ /** The `widgetBoard` service, as this module uses it. */
43
+ export interface WidgetBoardService {
44
+ readonly apiVersion: number;
45
+ registerWidgetType(registration: {
46
+ apiVersion: number;
47
+ provider: string;
48
+ directory: string;
49
+ }): Promise<WidgetBoardHandle>;
50
+ /**
51
+ * Present from the board generation that introduced capabilities.
52
+ *
53
+ * Probed, never assumed: an older board publishes no such method, and this
54
+ * provider then registers its data sources alone instead of failing.
55
+ */
56
+ registerCapability?(registration: WidgetBoardCapabilityRegistration): () => void;
57
+ }
58
+ /** The scoped context an inject callback receives. */
59
+ export interface WidgetBoardScope {
60
+ get(name: string): unknown;
61
+ logger: {
62
+ warn(message: string): void;
63
+ };
64
+ effect(callback: () => () => void, label?: string): void;
65
+ }
66
+ /**
67
+ * The host context, narrowed to what this module touches.
68
+ *
69
+ * A structural subset of the Cordis `Context`, so the caller casts once at the
70
+ * wiring site and a test can drive the real registration function with a
71
+ * plain object.
72
+ */
73
+ export interface WidgetBoardContext {
74
+ inject(names: string[], callback: (scope: WidgetBoardScope) => void): void;
75
+ }
76
+ /**
77
+ * The line registry this provider publishes when the composition hands one over.
78
+ *
79
+ * Deliberately a plain bag of already-resolved services rather than the pools
80
+ * themselves: the mapping's key is a line id the board also knows, its value is
81
+ * whatever that line's pool object is, and this module never learns which class
82
+ * it is talking to.
83
+ */
84
+ export interface WidgetBoardLineOptions {
85
+ /**
86
+ * This host's own origin, resolved per read.
87
+ *
88
+ * A thunk rather than a string because the web server may not have bound a
89
+ * port yet when this provider registers, and a value captured then would be a
90
+ * guess that outlives the fact.
91
+ */
92
+ origin(): string;
93
+ /** Line id → its pool. A line with no entry is reported as not installed. */
94
+ pools: Readonly<Record<string, LineAccountSource | undefined>>;
95
+ /** Test seam: the HTTP client the loopback reads use. */
96
+ fetchFn?: typeof fetch;
97
+ /** Test seam: the whole-read budget in milliseconds. */
98
+ timeoutMs?: number;
99
+ /**
100
+ * Line id → that line's quota client, for the lines that read a quota PER
101
+ * ACCOUNT (see `LINE_ACCOUNT_QUOTA_READERS` in the registry).
102
+ *
103
+ * Passed through untouched: the composition holds these clients, this module
104
+ * never learns which line they belong to, and a line omitted here is a line
105
+ * that keeps the pool's own single-account snapshot.
106
+ */
107
+ accountQuotaClients?: Readonly<Record<string, LineAccountQuotaClient | undefined>>;
108
+ }
109
+ /** What {@link registerWidgetBoard} is handed. */
110
+ export interface WidgetBoardProviderOptions {
111
+ /**
112
+ * The per-line registry, when the composition has one.
113
+ *
114
+ * Absent leaves this provider with nothing to register at all — no
115
+ * `line-card` data source and no line capabilities — which is exactly what a
116
+ * caller that has not wired the line pools wants. There is no ChatGPT-only
117
+ * fallback any more: one card per line is the whole contribution.
118
+ */
119
+ lines?: WidgetBoardLineOptions;
120
+ /** Test seam: overrides the widget directory found from `import.meta.url`. */
121
+ widgetsDirectory?: string;
122
+ }
123
+ /**
124
+ * Register this plugin's board contribution, if the host has a board.
125
+ *
126
+ * @param ctx - The host context; only `inject` is used.
127
+ * @param options - The line registry to publish through, and the widget directory override.
128
+ */
129
+ export declare function registerWidgetBoard(ctx: WidgetBoardContext, options: WidgetBoardProviderOptions): void;
130
+ /**
131
+ * This package's widget directory, resolved from the loaded module.
132
+ *
133
+ * `import.meta.url` points at `lib/index.js` in a built package and at a source
134
+ * file under `src/` in a test run, so the root is found by walking up to the
135
+ * `package.json` that names THIS package rather than by assuming a depth.
136
+ *
137
+ * @returns The absolute directory, or undefined when no such manifest was found.
138
+ */
139
+ export declare function widgetsDirectory(): string | undefined;
140
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../../src/host/widget-board/provider.ts"],"names":[],"mappings":"AAqCA,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EAEvB,MAAM,oBAAoB,CAAA;AAsB3B,4DAA4D;AAC5D,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B;AAED,gEAAgE;AAChE,MAAM,WAAW,iCAAiC;IAChD,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,CAAC,QAAQ,EAAE,mBAAmB,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAChE;AAED,+DAA+D;AAC/D,MAAM,WAAW,iCAAiC;IAChD,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;IAClC,WAAW,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,IAAI,CAAC,QAAQ,EAAE,mBAAmB,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACpG;AAED,sEAAsE;AACtE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE;QACvB,WAAW,CAAC,EAAE,iCAAiC,EAAE,CAAA;QACjD,YAAY,CAAC,EAAE,iCAAiC,EAAE,CAAA;KACnD,GAAG,MAAM,IAAI,CAAA;IACd,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB;AAED,yDAAyD;AACzD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,kBAAkB,CAAC,YAAY,EAAE;QAC/B,UAAU,EAAE,MAAM,CAAA;QAClB,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;KAClB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAC9B;;;;;OAKG;IACH,kBAAkB,CAAC,CAAC,YAAY,EAAE,iCAAiC,GAAG,MAAM,IAAI,CAAA;CACjF;AAED,sDAAsD;AACtD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAC1B,MAAM,EAAE;QAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;IACvC,MAAM,CAAC,QAAQ,EAAE,MAAM,MAAM,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,IAAI,CAAA;CAC3E;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;;OAMG;IACH,MAAM,IAAI,MAAM,CAAA;IAChB,6EAA6E;IAC7E,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,CAAC,CAAC,CAAA;IAC9D,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,KAAK,CAAA;IACtB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,GAAG,SAAS,CAAC,CAAC,CAAA;CACnF;AAED,kDAAkD;AAClD,MAAM,WAAW,0BAA0B;IACzC;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,sBAAsB,CAAA;IAC9B,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,kBAAkB,EAAE,OAAO,EAAE,0BAA0B,GAAG,IAAI,CA2EtG;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAGrD"}
@@ -2,6 +2,7 @@ import type { Context, Volatile } from '@deepseek-ai/cordis';
2
2
  import z from '@deepseek-ai/schemastery';
3
3
  import { type GuardOptions } from './host/reasoning-collapse-guard/index.ts';
4
4
  import { type NoAnswerResumeOptions } from './host/no-answer-resume/index.ts';
5
+ import type { ProgressUpdateLanguage } from './host/progress-updates/prompt.ts';
5
6
  /**
6
7
  * 运行期配置形状:标了 `volatile()` 的字段在 loader 解析之后是**活引用**。
7
8
  *
@@ -81,6 +82,13 @@ export interface Config {
81
82
  * 条提醒。默认 8(与 `NUDGE_THRESHOLD` 同一个数,两处不会漂移)。
82
83
  */
83
84
  progressUpdatesNudgeThreshold?: Volatile<number>;
85
+ /**
86
+ * 进展更新的输出语言:`auto` 跟随对话(默认)、`zh` 中文、`en` 英文。
87
+ *
88
+ * 只约束 `progress_update` 的标题与正文——提示词本身固定英文,用户看到的
89
+ * 文字才跟着这个字段走。同样是 `volatile()`:设置一保存就生效,不重挂插件行。
90
+ */
91
+ progressUpdatesLanguage?: Volatile<ProgressUpdateLanguage>;
84
92
  }
85
93
  /**
86
94
  * profile 里写的配置形状:volatile 字段在这里仍是普通值。
@@ -118,6 +126,8 @@ export interface ConfigInput {
118
126
  progressUpdates?: boolean;
119
127
  /** 进展更新的催促阈值(默认 8)。 */
120
128
  progressUpdatesNudgeThreshold?: number;
129
+ /** 进展更新的输出语言(默认 auto:跟随对话)。 */
130
+ progressUpdatesLanguage?: ProgressUpdateLanguage;
121
131
  }
122
132
  export declare const Config: z<ConfigInput, Config>;
123
133
  export declare const inject: string[];