@eddyskywalker/dsh-chatgpt-subscription 0.46.1 → 0.47.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 (90) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +22 -1
  3. package/lib/client.js +2639 -571
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +12000 -3591
  6. package/lib/plan-mode-pipeline.js +419 -0
  7. package/lib/types/client/hub/brand-icons.d.ts +1 -1
  8. package/lib/types/client/hub/brand-icons.d.ts.map +1 -1
  9. package/lib/types/client/hub/brand-svg.d.ts +4 -0
  10. package/lib/types/client/hub/brand-svg.d.ts.map +1 -1
  11. package/lib/types/client/hub/providers.d.ts.map +1 -1
  12. package/lib/types/client/index.d.ts +2 -0
  13. package/lib/types/client/index.d.ts.map +1 -1
  14. package/lib/types/client/locales-ru/index.d.ts.map +1 -1
  15. package/lib/types/client/locales-ru/progress-updates.d.ts.map +1 -1
  16. package/lib/types/client/locales-ru/workbuddy.d.ts +10 -0
  17. package/lib/types/client/locales-ru/workbuddy.d.ts.map +1 -0
  18. package/lib/types/client/progress-updates/locales.d.ts +23 -5
  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 -1
  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 +1 -1
  23. package/lib/types/client/progress-updates/settings-section.d.ts.map +1 -1
  24. package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts +34 -0
  25. package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts.map +1 -0
  26. package/lib/types/client/workbuddy/WorkBuddySection.d.ts +91 -0
  27. package/lib/types/client/workbuddy/WorkBuddySection.d.ts.map +1 -0
  28. package/lib/types/client/workbuddy/locales.d.ts +768 -0
  29. package/lib/types/client/workbuddy/locales.d.ts.map +1 -0
  30. package/lib/types/client/workbuddy/styles.d.ts +21 -0
  31. package/lib/types/client/workbuddy/styles.d.ts.map +1 -0
  32. package/lib/types/client/workbuddy/useWorkBuddySection.d.ts +149 -0
  33. package/lib/types/client/workbuddy/useWorkBuddySection.d.ts.map +1 -0
  34. package/lib/types/compat.d.ts +1 -1
  35. package/lib/types/entry-plan-mode-pipeline.d.ts +191 -0
  36. package/lib/types/entry-plan-mode-pipeline.d.ts.map +1 -0
  37. package/lib/types/host/agent-preset.d.ts.map +1 -1
  38. package/lib/types/host/cache-warmup/contracts.d.ts +5 -1
  39. package/lib/types/host/cache-warmup/contracts.d.ts.map +1 -1
  40. package/lib/types/host/cache-warmup/install.d.ts.map +1 -1
  41. package/lib/types/host/cache-warmup/projection.d.ts.map +1 -1
  42. package/lib/types/host/cache-warmup/retrieval-intent.d.ts +18 -0
  43. package/lib/types/host/cache-warmup/retrieval-intent.d.ts.map +1 -0
  44. package/lib/types/host/cache-warmup/settings.d.ts +9 -2
  45. package/lib/types/host/cache-warmup/settings.d.ts.map +1 -1
  46. package/lib/types/host/common/capabilities.d.ts.map +1 -1
  47. package/lib/types/host/common/model-request-control.d.ts +1 -1
  48. package/lib/types/host/common/model-request-control.d.ts.map +1 -1
  49. package/lib/types/host/common/request-diagnostics.d.ts +1 -1
  50. package/lib/types/host/common/request-diagnostics.d.ts.map +1 -1
  51. package/lib/types/host/compaction-prompt.d.ts +129 -0
  52. package/lib/types/host/compaction-prompt.d.ts.map +1 -0
  53. package/lib/types/host/preset-sync.d.ts.map +1 -1
  54. package/lib/types/host/workbuddy/account-pool.d.ts +389 -0
  55. package/lib/types/host/workbuddy/account-pool.d.ts.map +1 -0
  56. package/lib/types/host/workbuddy/adapter.d.ts +249 -0
  57. package/lib/types/host/workbuddy/adapter.d.ts.map +1 -0
  58. package/lib/types/host/workbuddy/atrest.d.ts +98 -0
  59. package/lib/types/host/workbuddy/atrest.d.ts.map +1 -0
  60. package/lib/types/host/workbuddy/checkin.d.ts +150 -0
  61. package/lib/types/host/workbuddy/checkin.d.ts.map +1 -0
  62. package/lib/types/host/workbuddy/client.d.ts +214 -0
  63. package/lib/types/host/workbuddy/client.d.ts.map +1 -0
  64. package/lib/types/host/workbuddy/dsml.d.ts +55 -0
  65. package/lib/types/host/workbuddy/dsml.d.ts.map +1 -0
  66. package/lib/types/host/workbuddy/guardrails.d.ts +111 -0
  67. package/lib/types/host/workbuddy/guardrails.d.ts.map +1 -0
  68. package/lib/types/host/workbuddy/identity.d.ts +71 -0
  69. package/lib/types/host/workbuddy/identity.d.ts.map +1 -0
  70. package/lib/types/host/workbuddy/mapper.d.ts +238 -0
  71. package/lib/types/host/workbuddy/mapper.d.ts.map +1 -0
  72. package/lib/types/host/workbuddy/model-catalog.d.ts +217 -0
  73. package/lib/types/host/workbuddy/model-catalog.d.ts.map +1 -0
  74. package/lib/types/host/workbuddy/oauth.d.ts +47 -0
  75. package/lib/types/host/workbuddy/oauth.d.ts.map +1 -0
  76. package/lib/types/host/workbuddy/outbound-identity.d.ts +139 -0
  77. package/lib/types/host/workbuddy/outbound-identity.d.ts.map +1 -0
  78. package/lib/types/host/workbuddy/routes.d.ts +56 -0
  79. package/lib/types/host/workbuddy/routes.d.ts.map +1 -0
  80. package/lib/types/host/workbuddy/token-store.d.ts +370 -0
  81. package/lib/types/host/workbuddy/token-store.d.ts.map +1 -0
  82. package/lib/types/host/workbuddy/types.d.ts +179 -0
  83. package/lib/types/host/workbuddy/types.d.ts.map +1 -0
  84. package/lib/types/index.d.ts +35 -0
  85. package/lib/types/index.d.ts.map +1 -1
  86. package/lib/types/shared/workbuddy-contracts.d.ts +531 -0
  87. package/lib/types/shared/workbuddy-contracts.d.ts.map +1 -0
  88. package/package.json +6 -2
  89. package/presets/dispatch/README.md +57 -3
  90. package/presets/dispatch/agent.cordis.yml +42 -13
@@ -0,0 +1,249 @@
1
+ import { LlmAdapter, LlmError, ReasoningEffortId, type GenerateOptions, type LlmModelInfo, type LlmProviderInfo, type LlmResolvedModelInfo, type PreparedAdapterCall, type ResolvedRetryPolicy, type StreamChunk } from '@deepseek-ai/dsh-llm';
2
+ import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment';
3
+ import { PROVIDER_ID, PROVIDER_NAME } from './types.ts';
4
+ import { FileCredentialStore, FileModelSettingsStore, type WorkBuddyPreferenceStore } from './token-store.ts';
5
+ import { type WorkBuddyModelEntry } from './model-catalog.ts';
6
+ import { type AttachmentImageReader } from './mapper.ts';
7
+ import { type WorkBuddyAccountRestrictionDto } from '../../shared/workbuddy-contracts.ts';
8
+ import type { WorkBuddyCredentials } from './token-store.ts';
9
+ import { type WorkBuddyUsageLedger } from './guardrails.ts';
10
+ /**
11
+ * Effort this route materializes when the caller names none.
12
+ *
13
+ * Preference order: the user's configured level when the model accepts it,
14
+ * otherwise the level the gateway's own catalog declares for that model (the
15
+ * same default the official CLI applies), otherwise nothing — which leaves the
16
+ * provider's own default in charge. A configured level the model does not
17
+ * accept is ignored rather than sent, since the endpoint rejects an unsupported
18
+ * level with `code 11150`.
19
+ */
20
+ export declare function resolveDefaultReasoningEffort(efforts: readonly string[], configuredEffort?: string | null, modelDefaultEffort?: string | null): ReasoningEffortId | undefined;
21
+ /** Cooldown a 429 imposes when the service names no reset instant. */
22
+ export declare const POOL_COOLDOWN_MS: number;
23
+ /**
24
+ * The account pool this adapter drives, declared STRUCTURALLY.
25
+ *
26
+ * The pool module (`account-pool.ts`) and the settings routes are outside this
27
+ * file's boundary — Wave 3 owns them — so the adapter cannot import the class.
28
+ * Declaring the shape it calls has one property that matters here: this file is
29
+ * typechecked against the CONTRACT, so a method renamed on the pool side fails
30
+ * the build instead of failing at run time in the middle of a rotation loop.
31
+ *
32
+ * `markAccountRestriction` is the one member the pool worker FROZE for Wave 2B:
33
+ * code 11140 is an account verdict (who is asking), not a model verdict, and a
34
+ * `cooldownUntil` on the account or on a model cannot express "this account is
35
+ * barred from everything".
36
+ */
37
+ export interface WorkBuddyAccountPool {
38
+ listAccounts(): Promise<readonly {
39
+ id: string;
40
+ }[]>;
41
+ getEffectiveCredential(tried: ReadonlySet<string>, fetchFn: typeof fetch, model?: string): Promise<{
42
+ account: {
43
+ id: string;
44
+ };
45
+ credentials: WorkBuddyCredentials;
46
+ }>;
47
+ renewCredential(accountId: string, fetchFn: typeof fetch, current: WorkBuddyCredentials): Promise<WorkBuddyCredentials>;
48
+ hasAnotherAvailableAccount(tried: ReadonlySet<string>): Promise<boolean>;
49
+ hasAnotherAvailableAccountFor(tried: ReadonlySet<string>, model: string): Promise<boolean>;
50
+ markCooldown(accountId: string, ms: number, reason: string): Promise<unknown>;
51
+ markModelCooldown(accountId: string, model: string, until: number): void;
52
+ /** Freeze this account out of every model after code 11140. */
53
+ markAccountRestriction(accountId: string, restriction: WorkBuddyAccountRestrictionDto): Promise<void>;
54
+ }
55
+ /**
56
+ * The pool's own "everything is stopped" error.
57
+ *
58
+ * Read structurally (by `name`) rather than by `instanceof`: the class lives in
59
+ * the pool module this file may not import, and a plugin build that loaded the
60
+ * pool and the adapter through two module instances would fail an `instanceof`
61
+ * check that the name comparison passes.
62
+ */
63
+ export interface WorkBuddyPoolPausedErrorLike extends Error {
64
+ name: 'WorkBuddyPoolPausedError';
65
+ /** Why the whole pool is stopped; composed by the host, never a token. */
66
+ pauseReason?: string;
67
+ /** Unix milliseconds the pause lifts on its own, when it does. */
68
+ pausedUntil?: number;
69
+ }
70
+ /** Whether one thrown value is the pool's whole-pool pause. */
71
+ export declare function isPoolPausedError(error: unknown): error is WorkBuddyPoolPausedErrorLike;
72
+ /**
73
+ * Which of the account's models the picker may offer.
74
+ *
75
+ * The stored list is kept relative to what the ACCOUNT can serve, and the
76
+ * shipped default is not a stored preference: a user who never visited the
77
+ * picker has exactly the shipped defaults stored, and that state has to mean
78
+ * "everything this account can serve" — otherwise a model the catalog gained
79
+ * after the last visit would be hidden from someone who never hid it.
80
+ */
81
+ export declare function resolveEnabledModelIds(stored: readonly string[], available: readonly string[], enabled?: boolean): string[];
82
+ /** Most system texts this process remembers (FIFO beyond it). */
83
+ export declare const REFUSED_SYSTEM_MEMORY_LIMIT = 256;
84
+ /** Remember one refused system text, evicting the oldest past the limit. */
85
+ export declare function rememberRefusedSystemKey(key: string): void;
86
+ /** Whether this process has already been refused for that system text. */
87
+ export declare function refusedSystemKeyKnown(key: string): boolean;
88
+ /** How many system texts are remembered (test and diagnostics seam). */
89
+ export declare function refusedSystemKeyCount(): number;
90
+ /** Forget every remembered refusal (test seam; never called by the adapter). */
91
+ export declare function clearRefusedSystemKeys(): void;
92
+ export interface WorkBuddyAdapterOptions {
93
+ /**
94
+ * Per-account daily token counters behind the local guardrails.
95
+ *
96
+ * Absent means the guardrails cannot be evaluated, so a deployment without it
97
+ * never refuses a request for a reason nothing is counting.
98
+ */
99
+ usageLedger?: WorkBuddyUsageLedger;
100
+ fetchFn?: typeof fetch;
101
+ attachments?: AttachmentImageReader;
102
+ /** Live catalog loader seam; defaults to the gateway `/v3/config` call. */
103
+ loadCatalog?: (credentials: WorkBuddyCredentials) => Promise<WorkBuddyModelEntry[]>;
104
+ /**
105
+ * Multi-account pool this adapter rotates through.
106
+ *
107
+ * Absent leaves the line on its single-credential path, which is what the
108
+ * headless tests and any caller that predates the pool use.
109
+ */
110
+ accountPool?: WorkBuddyAccountPool;
111
+ }
112
+ export declare class WorkBuddyAdapter extends LlmAdapter {
113
+ private readonly store;
114
+ private readonly modelSettings;
115
+ private readonly preferences?;
116
+ private readonly options;
117
+ /** Null keeps the pre-pool single-credential path. */
118
+ private readonly accountPool;
119
+ constructor(store?: FileCredentialStore, modelSettings?: FileModelSettingsStore, preferences?: WorkBuddyPreferenceStore | undefined, options?: WorkBuddyAdapterOptions);
120
+ providerInfo(provider: string): LlmProviderInfo;
121
+ providerRetryPolicy(): ResolvedRetryPolicy;
122
+ imageRequestPricing(): undefined;
123
+ /**
124
+ * Request version the harness should hand this route for one image.
125
+ *
126
+ * This is the other half of the request image budget and it has to come from
127
+ * the same place: the shared kernel decides the target (long edge 1024,
128
+ * 256 KiB per image) and the shared budget decides what still fits, so a
129
+ * mapper cannot ask for a target the harness does not produce, and cannot
130
+ * send an image the kernel already paid to downscale. Answering undefined
131
+ * here used to mean send-as-stored while the mapper applied its own private
132
+ * 12 MB ceiling, which is exactly the drift this pairing removes.
133
+ */
134
+ imageRequestTarget(_provider: string, _model: string, image: ImageAttachmentRef): {
135
+ width: number;
136
+ height: number;
137
+ maxBytes: number;
138
+ };
139
+ private settings;
140
+ private credentials;
141
+ /**
142
+ * Catalog for the picker: the live gateway listing when reachable, the
143
+ * shipped table otherwise.
144
+ *
145
+ * The gateway is the authority on capabilities, so its answer replaces the
146
+ * fallback rather than merging with it — a model whose context window changed
147
+ * upstream must not keep a stale local value.
148
+ */
149
+ private catalog;
150
+ /**
151
+ * Models the picker may offer.
152
+ *
153
+ * The catalog is filtered by the account's own region: asking a region for a
154
+ * model it does not serve answers 400 `code 11102`, so offering one would
155
+ * hand the user a model that cannot work.
156
+ */
157
+ listModels(provider?: string): Promise<readonly LlmModelInfo[]>;
158
+ resolveModel(provider: string, modelId: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
159
+ prepareCall(provider: string, model: string, signal?: AbortSignal): Promise<PreparedAdapterCall>;
160
+ stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
161
+ /**
162
+ * Effort this request should carry, or `undefined` to send none.
163
+ *
164
+ * Order: the caller's explicit choice, then the user's configured level, then
165
+ * the level the gateway catalog declares for this model. The last step
166
+ * matters because the endpoint returns an **empty `reasoning_content`** when
167
+ * no `reasoning_effort` is present, even for a reasoning-only model: measured
168
+ * on `deepseek-v4.1-flash`, the same prompt yields 0 reasoning characters
169
+ * with no field and 130-215 with one. Omitting it therefore silently drops
170
+ * the model's thinking instead of letting the provider pick, so the catalog's
171
+ * own default (which is what the official CLI sends) is materialized here.
172
+ *
173
+ * A candidate the model does not accept is discarded rather than sent, since
174
+ * the endpoint rejects an unsupported level with `code 11150`.
175
+ */
176
+ /**
177
+ * Accounts the LOCAL guardrails refuse for this model right now.
178
+ *
179
+ * Reads only numbers this plugin already owns — the billing snapshot's
180
+ * remaining credits and this line's own token counters — so it never becomes a
181
+ * second, disagreeing source of truth about the upstream allowance.
182
+ */
183
+ private guardrailBlockedAccounts;
184
+ private effortFor;
185
+ private requestStream;
186
+ /**
187
+ * Re-read the stored credential, for a token another process may have written.
188
+ *
189
+ * The desktop app and any sibling plugin share this directory, and a token
190
+ * written there is already the newest one available: refreshing over it would
191
+ * rotate the account's refresh token out from under whoever signed in last.
192
+ * A failed read answers null — it is a fallback, not a verdict.
193
+ */
194
+ private rereadCredential;
195
+ /**
196
+ * Count this request's billed tokens off its usage frame.
197
+ *
198
+ * Both protocols send exactly one usage frame at the end; the cache counts are
199
+ * added back because the aggregate the surfaces report excludes them, so a
200
+ * cached turn would otherwise be recorded as almost free.
201
+ */
202
+ private countedChunks;
203
+ /**
204
+ * Read one SSE body into chunks, protocol-agnostically.
205
+ *
206
+ * Bytes on the wire are the liveness signal: a heartbeat or status frame that
207
+ * produces no displayable chunk still proves the connection is alive, so the
208
+ * watchdog timer is reset at the transport layer, not at the parser.
209
+ */
210
+ private drainStream;
211
+ }
212
+ /**
213
+ * The failure a 11140 is reported as.
214
+ *
215
+ * Account-scoped, so it is classified apart from every model-scoped refusal: the
216
+ * message says the ACCOUNT is barred (not that a model is unavailable, not that
217
+ * a quota window is full), because the fix is a different account or a release
218
+ * from the service, and no retry can help.
219
+ */
220
+ export declare function accountRestrictedFailure(detail: string, status: number): LlmError;
221
+ /**
222
+ * Map one failed HTTP response onto a DSH failure.
223
+ *
224
+ * The subscription reports its own conditions inside a JSON `code` while the
225
+ * status line stays generic, so the body is read for the specific cases the
226
+ * status alone cannot express — notably the quota signal, whose message carries
227
+ * the instant the allowance resets.
228
+ */
229
+ export declare function classifyFailure(status: number, detail: string, headers?: Headers): LlmError;
230
+ /**
231
+ * The reset instant a quota refusal names, as a delay from now.
232
+ *
233
+ * A 24h allowance that is exhausted answers 429 / `code 6004` with the wall
234
+ * clock it lifts — but only in the MESSAGE, never in a header, and in two
235
+ * realm-specific wordings (measured: intl "… resets at 2026-09-20 10:50:48
236
+ * UTC+8", cn "… 将在 2026-10-09 14:44:59 UTC+8 重置"). Reading the status alone
237
+ * therefore loses the only fact that says how long the account is out, and the
238
+ * pool parks a 24-hour limit for five minutes before trying it again.
239
+ *
240
+ * Deliberately tolerant, in the same direction as their gateway: an unparseable
241
+ * body yields `undefined` (callers keep their default cooldown) rather than an
242
+ * error, because this runs on a failure path. An absent `UTC±h` marker means
243
+ * UTC, which is how the sibling implementation reads it too.
244
+ */
245
+ export declare function readRateLimitReset(detail: string, now?: number): number | undefined;
246
+ /** Read the subscription's own numeric error code out of a response body. */
247
+ export declare function readErrorCode(detail: string): number | null;
248
+ export { PROVIDER_ID, PROVIDER_NAME };
249
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/host/workbuddy/adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * `$wbEncrypted` at-rest credential envelope.
3
+ *
4
+ * The CodeBuddy/WorkBuddy desktop client stopped writing plaintext tokens on
5
+ * 2026-09-24: `auth.accessToken` / `auth.refreshToken` became
6
+ * `{"$wbEncrypted": 1, "envelope": base64}` (the domestic build also seals
7
+ * `nickname` / `phoneNumber`). Reading such a file the way this plugin used to
8
+ * yields the envelope TEXT as the bearer token, so every request answers 401 —
9
+ * the adoption path has to decrypt before it can use the credential.
10
+ *
11
+ * The scheme below is transcribed from the client's `packages/at-rest-crypto`
12
+ * as reimplemented by workbuddy2api-hub (`wb_atrest.py`, MIT); the framing
13
+ * constants are the part that must match byte for byte:
14
+ *
15
+ * key = sha256(atRestSecretKey as an ASCII string) # the protector key
16
+ * keyId = sha256(key).hex[0..16] # `protectorKeyId`
17
+ * AAD = "WB-AAD\0" | 0x01 | LP(fileMagic) | LP("sym-v1")
18
+ * | u32(suite) | LP(keyId) | framingCode | 0x00 | 0x00
19
+ * envelope = base64(JSON{suite, keyId, nonce, authTag, ciphertext}) # AES-256-GCM
20
+ * framing : the keyblob's wrapped master key is `WBEF1`/1, a sealed `.info`
21
+ * field is `WBEV1`/2 — the SAME protector key opens both.
22
+ *
23
+ * Key material never leaves the process and is never logged: the user pastes it
24
+ * once, it is stored through the platform credential store (DPAPI / Keychain /
25
+ * Secret Service), and every read re-validates it against the client's own
26
+ * keyblob when that file exists.
27
+ */
28
+ /** Field name the client uses to mark a sealed value. */
29
+ export declare const ENVELOPE_KEY = "$wbEncrypted";
30
+ /** Framing kinds and the code each carries in the AAD. */
31
+ declare const FRAMING: {
32
+ readonly file: {
33
+ readonly magic: "WBEF1";
34
+ readonly code: 1;
35
+ };
36
+ readonly field: {
37
+ readonly magic: "WBEV1";
38
+ readonly code: 2;
39
+ };
40
+ };
41
+ type Framing = keyof typeof FRAMING;
42
+ /** Every failure the at-rest path can report to a user. */
43
+ export declare class AtRestError extends Error {
44
+ constructor(message: string);
45
+ }
46
+ /** The GCM associated data, byte-identical to the client's. */
47
+ export declare function associatedData(keyId: string, suite: number, framing: Framing): Buffer;
48
+ /** `protectorKeyId` / `envelope.keyId`: the first 16 hex characters of sha256(key). */
49
+ export declare function deriveKeyId(key: Buffer): string;
50
+ /**
51
+ * Whether a value is a sealed envelope rather than plaintext.
52
+ *
53
+ * Older clients sometimes stored the whole envelope as a JSON STRING in the
54
+ * field, so that shape is recognised too.
55
+ */
56
+ export declare function isSealedValue(value: unknown): boolean;
57
+ interface SealedEnvelope {
58
+ suite: number;
59
+ keyId: string;
60
+ nonce: Buffer;
61
+ authTag: Buffer;
62
+ ciphertext: Buffer;
63
+ }
64
+ /** Split one envelope into its GCM parts. */
65
+ export declare function parseEnvelope(value: unknown): SealedEnvelope;
66
+ /** Open one envelope with the protector key, returning the plaintext bytes. */
67
+ export declare function openEnvelope(key: Buffer, value: unknown, framing: Framing): Buffer;
68
+ /** Decrypt a field that may be sealed, leaving plaintext values untouched. */
69
+ export declare function openSealedField(key: Buffer, value: unknown): string;
70
+ /**
71
+ * Normalise a pasted secret into the 32-byte protector key.
72
+ *
73
+ * Two spellings are accepted, neither requiring the user to compute anything:
74
+ * a 64-character hex protector key (used as-is), or the 44-character base64
75
+ * `atRestSecretKey` the client carries in its payload — that one is hashed as
76
+ * the STRING, which is what produces the protector key.
77
+ */
78
+ export declare function parseKeyText(text: string): Buffer;
79
+ /** Path of the client's keyblob, or null when the client is not installed here. */
80
+ export declare function keyBlobPath(): string | null;
81
+ /**
82
+ * Validate a protector key against the client's own keyblob.
83
+ *
84
+ * This is the check that turns a typo into an error instead of a mystery: the
85
+ * key must match the `static-v1` slot's `protectorKeyId` and must unwrap a
86
+ * 32-byte master whose derived id matches the blob's own `keyId`. Returns
87
+ * `false` when there is no keyblob to check against (the desktop client is not
88
+ * installed on this machine) — absence of evidence, not evidence of a bad key.
89
+ */
90
+ export declare function verifyKeyAgainstKeyBlob(key: Buffer): Promise<boolean>;
91
+ /** Install the protector key for this process (already persisted by the caller). */
92
+ export declare function setActiveAtRestKey(key: Buffer | null): void;
93
+ /** The protector key this process holds, if any. */
94
+ export declare function activeAtRestKey(): Buffer | null;
95
+ /** Whether sealed credentials can be opened right now. */
96
+ export declare function hasAtRestKey(): boolean;
97
+ export {};
98
+ //# sourceMappingURL=atrest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atrest.d.ts","sourceRoot":"","sources":["../../../../src/host/workbuddy/atrest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH,yDAAyD;AACzD,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,0DAA0D;AAC1D,QAAA,MAAM,OAAO;;;;;;;;;CAGH,CAAC;AAEX,KAAK,OAAO,GAAG,MAAM,OAAO,OAAO,CAAC;AAQpC,2DAA2D;AAC3D,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAeD,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAWrF;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAUrD;AAED,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD,6CAA6C;AAC7C,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAsB5D;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAkBlF;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAKnE;AAKD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQjD;AAUD,mFAAmF;AACnF,wBAAgB,WAAW,IAAI,MAAM,GAAG,IAAI,CAM3C;AAwBD;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAkB3E;AAID,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAE3D;AAED,oDAAoD;AACpD,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAE/C;AAED,0DAA0D;AAC1D,wBAAgB,YAAY,IAAI,OAAO,CAEtC"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Daily check-in scheduler for the CN-region billing activity.
3
+ *
4
+ * Ported from workbuddy2api's `daily_checkin.py` and adapted to this host:
5
+ * the cron job becomes an in-process timer (the plugin runs inside the DSH
6
+ * host, so a day the host never runs is a day nothing signs in — accepted and
7
+ * documented), and the per-file state JSON becomes one state document under
8
+ * the harness home. The semantics are kept exactly:
9
+ *
10
+ * - **CN only.** The international deployment exposes no check-in surface, so
11
+ * those accounts are skipped rather than failing daily.
12
+ * - **Idempotent.** The activity status is queried first; an account already
13
+ * signed in (by anyone) is only recorded. An account whose activity reports
14
+ * no entitlement is parked (see {@link CHECKIN_INACTIVE_RECHECK_MS}) rather
15
+ * than abandoned for the day: the host often starts before the activity's
16
+ * daily opening, and treating that first answer as final cost the account its
17
+ * only chance to sign in. Once everyone is settled, a tick sends no requests.
18
+ * - **Bounded.** A failing account is retried at most {@link CHECKIN_ATTEMPT_CAP}
19
+ * times a day, so a broken account cannot turn the ten-minute tick into a
20
+ * request loop. A manual run ignores the cap and the window, like the
21
+ * reference script's `--now`, and is queued behind an in-flight run rather
22
+ * than dropped into it (a click must actually mean "try again now").
23
+ *
24
+ * Tokens stay host-side: the only write beyond the state file is the existing
25
+ * credential store's refresh write-back, reused here unchanged.
26
+ */
27
+ import { type FileCredentialStore } from './token-store.ts';
28
+ import type { WorkBuddyCheckinSettings, WorkBuddyCheckinSummary } from '../../shared/workbuddy-contracts.ts';
29
+ /** Activity status surface; answers whether today is signed in already. */
30
+ export declare const CHECKIN_STATUS_PATH = "/billing/meter/checkin-activity-status";
31
+ /** Check-in surface; credits are granted by posting here once a day. */
32
+ export declare const CHECKIN_PATH = "/billing/meter/daily-checkin";
33
+ /**
34
+ * Scheduler cadence. The first tick at host startup is the daily run; the
35
+ * interval keeps a long-lived process signing in on later days without a
36
+ * restart. Idle ticks cost no requests — the day state short-circuits them.
37
+ */
38
+ export declare const CHECKIN_TICK_MS: number;
39
+ /** Daily retry ceiling for one account after a failed attempt. */
40
+ export declare const CHECKIN_ATTEMPT_CAP = 3;
41
+ export declare const CHECKIN_TIMEOUT_MS = 20000;
42
+ /**
43
+ * How long an unentitled account waits before the activity is polled again.
44
+ *
45
+ * The activity opens on its own schedule, so the first inactive answer of the
46
+ * day is frequently 'not open yet' rather than 'no entitlement today'. Hourly
47
+ * re-checks keep a host that booted early from missing the day, while still
48
+ * costing at most one status request per hour per account.
49
+ */
50
+ export declare const CHECKIN_INACTIVE_RECHECK_MS: number;
51
+ /**
52
+ * Random pause between two accounts in one pass.
53
+ *
54
+ * Sequential accounts already serialise their requests, but they still arrive as
55
+ * one tight cluster from one outbound IP; a dozen-account pool doing that at the
56
+ * same minute is the burst pattern the sibling gateway added jitter for after
57
+ * seeing upstream rate-limit whole pools.
58
+ */
59
+ export declare const CHECKIN_JITTER_MIN_MS = 2000;
60
+ export declare const CHECKIN_JITTER_MAX_MS = 5000;
61
+ /** State document the scheduler keeps beside the other plugin stores. */
62
+ export declare function checkinStatePath(): string;
63
+ /** Local calendar day an instant belongs to; state entries are keyed by it. */
64
+ export declare function localDateString(nowMs: number): string;
65
+ export interface WorkBuddyCheckinServiceOptions {
66
+ fetchFn?: typeof fetch;
67
+ /** State document path; tests redirect it, production uses {@link checkinStatePath}. */
68
+ statePath?: string;
69
+ /** Live preferences, re-read on every tick so the toggle applies at once. */
70
+ settings: () => WorkBuddyCheckinSettings;
71
+ /**
72
+ * Resolves once the preference store has read its stored document.
73
+ *
74
+ * Optional for callers whose settings are already in memory; the host passes
75
+ * the preference store's own warmup so the startup pass cannot act on a
76
+ * default that the stored document is about to overwrite.
77
+ */
78
+ ready?: () => Promise<void>;
79
+ /** Clock injection for tests. */
80
+ now?: () => number;
81
+ /** Wait between two accounts in one pass; injected so tests run without delays. */
82
+ pause?: (ms: number) => Promise<void>;
83
+ /** Jitter source; injected so a test can pin the delay it caused. */
84
+ random?: () => number;
85
+ logger?: {
86
+ info(message: string): void;
87
+ warn(message: string): void;
88
+ };
89
+ }
90
+ /**
91
+ * The check-in scheduler. One instance per plugin load; the host owns the
92
+ * interval and clears it from the same `ctx.effect` that created it.
93
+ */
94
+ export declare class WorkBuddyCheckinService {
95
+ private readonly store;
96
+ private readonly options;
97
+ private readonly fetchFn;
98
+ private readonly statePath;
99
+ private readonly now;
100
+ private readonly pause;
101
+ private readonly random;
102
+ private readonly logger;
103
+ private state;
104
+ private loaded;
105
+ /** Passes waiting to run, in order; `true` marks a manual pass. */
106
+ private readonly queue;
107
+ /** The drain loop currently working the queue, if any. */
108
+ private draining;
109
+ private lastRunAt;
110
+ /** Memoized preference warmup, so it is awaited once however many passes run. */
111
+ private readyWait;
112
+ constructor(store: FileCredentialStore, options: WorkBuddyCheckinServiceOptions);
113
+ /**
114
+ * One scheduler pass. Automatic passes honour the toggle and the retry cap;
115
+ * a manual pass (`manual: true`, the card's "check in now") ignores both
116
+ * but still respects an account already signed in today.
117
+ *
118
+ * A manual pass that lands while a run is already in flight is *queued*, not
119
+ * absorbed: joining the running pass would silently discard the one thing the
120
+ * button promises, that the retry cap and the toggle are bypassed now.
121
+ */
122
+ tick(manual?: boolean): Promise<void>;
123
+ /** Run queued passes one after another until the queue empties. */
124
+ private drain;
125
+ private runQueue;
126
+ private run;
127
+ /** Wait for the preference store's warmup read, once. */
128
+ private ready;
129
+ /** Check one account in, recording the outcome in its today's entry. */
130
+ private checkinOne;
131
+ /** Record a confirmed sign-in, clearing the transient failure bookkeeping. */
132
+ private markSignedIn;
133
+ /**
134
+ * Refresh a token the server rejected, bypassing the store's expiry check.
135
+ *
136
+ * `ensureFresh` only acts on a locally expired token, so a session the server
137
+ * revoked early would otherwise fail every retry until the file's own clock
138
+ * caught up. The rotation is written back through the store either way.
139
+ */
140
+ private forceRefresh;
141
+ /**
142
+ * The aggregate the settings card renders. Reads only local state and the
143
+ * account list; it never spends a network request.
144
+ */
145
+ summary(): Promise<WorkBuddyCheckinSummary>;
146
+ private load;
147
+ private save;
148
+ private post;
149
+ }
150
+ //# sourceMappingURL=checkin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkin.d.ts","sourceRoot":"","sources":["../../../../src/host/workbuddy/checkin.ts"],"names":[],"mappings":"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"}