@eddyskywalker/dsh-chatgpt-subscription 0.13.2 → 0.15.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.
- package/CHANGELOG.md +54 -0
- package/README.md +76 -8
- package/lib/client.js +183 -115
- package/lib/client.js.map +1 -1
- package/lib/index.js +1110 -76
- package/lib/types/client/CodexSubscriptionSection.d.ts +1 -1
- package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
- package/lib/types/client/ProviderHubSection.d.ts.map +1 -1
- package/lib/types/client/api.d.ts +12 -0
- package/lib/types/client/api.d.ts.map +1 -1
- package/lib/types/client/claude/ClaudeSection.d.ts.map +1 -1
- package/lib/types/client/claude/locales.d.ts +2 -11
- package/lib/types/client/claude/locales.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +13 -1
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/host/claude/model-catalog.d.ts +42 -20
- package/lib/types/host/claude/model-catalog.d.ts.map +1 -1
- package/lib/types/host/claude/types.d.ts +7 -2
- package/lib/types/host/claude/types.d.ts.map +1 -1
- package/lib/types/host/codex-account-pool.d.ts +129 -1
- package/lib/types/host/codex-account-pool.d.ts.map +1 -1
- package/lib/types/host/codex-adopt.d.ts +255 -0
- package/lib/types/host/codex-adopt.d.ts.map +1 -0
- package/lib/types/host/reasoning-collapse-guard/index.d.ts +166 -0
- package/lib/types/host/reasoning-collapse-guard/index.d.ts.map +1 -1
- package/lib/types/host/routes.d.ts +11 -1
- package/lib/types/host/routes.d.ts.map +1 -1
- package/lib/types/host/token-store.d.ts +26 -1
- package/lib/types/host/token-store.d.ts.map +1 -1
- package/lib/types/host/workbuddy/client.d.ts +1 -1
- package/lib/types/host/workbuddy/client.d.ts.map +1 -1
- package/lib/types/host/workbuddy/model-catalog.d.ts +77 -4
- package/lib/types/host/workbuddy/model-catalog.d.ts.map +1 -1
- package/lib/types/host/workbuddy/routes.d.ts +7 -1
- package/lib/types/host/workbuddy/routes.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/contracts.d.ts +22 -0
- package/lib/types/shared/contracts.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OPT-IN adoption of a pre-existing Codex CLI sign-in.
|
|
3
|
+
*
|
|
4
|
+
* WHAT THIS IS FOR. A user who already runs the unmodified Codex CLI is already
|
|
5
|
+
* signed in to the very subscription this provider serves. Asking them to sign in
|
|
6
|
+
* a second time is pure friction, so this module offers the one thing that
|
|
7
|
+
* removes it: reading back the credential the CLI itself stored in
|
|
8
|
+
* `$CODEX_HOME/auth.json` (`~/.codex/auth.json` when the variable is unset). It
|
|
9
|
+
* is opt-in — nothing here runs until the user asks for it.
|
|
10
|
+
*
|
|
11
|
+
* ---------------------------------------------------------------------------
|
|
12
|
+
* RULE 1 — THIS MODULE NEVER WRITES. IT IS A READER, AND ONLY A READER.
|
|
13
|
+
* ---------------------------------------------------------------------------
|
|
14
|
+
* It must not create, modify, move or delete any file belonging to the Codex CLI.
|
|
15
|
+
* No file this module touches is ever opened for writing, no directory is
|
|
16
|
+
* created, nothing is renamed and nothing is unlinked. The guarantee is
|
|
17
|
+
* structural rather than a promise in prose: the module imports exactly two
|
|
18
|
+
* functions BY NAME from 'node:fs/promises' — readFile and stat — instead of the
|
|
19
|
+
* whole namespace, so introducing a write would require a visible change to the
|
|
20
|
+
* import list, which is the line a reviewer reads first. Nothing exported here
|
|
21
|
+
* writes. The tests assert the stronger, observable form of the rule: a
|
|
22
|
+
* credential file's bytes, size and mtime are identical before and after both
|
|
23
|
+
* entry points run, and its directory gains no entries.
|
|
24
|
+
*
|
|
25
|
+
* ---------------------------------------------------------------------------
|
|
26
|
+
* RULE 2 — PRESENCE AND CONTENT ARE TWO SEPARATE FUNCTIONS
|
|
27
|
+
* ---------------------------------------------------------------------------
|
|
28
|
+
* codexCliCredentialPresence() is cheap enough to call on plugin startup and
|
|
29
|
+
* answers only yes/no: it stats the candidate and never opens it for reading. It
|
|
30
|
+
* exists so the settings card can offer the import before the user has agreed to
|
|
31
|
+
* it, and so a user who never opts in never has their token read at all.
|
|
32
|
+
*
|
|
33
|
+
* readCodexCliCredentials() is the full read, and it is called only AFTER the
|
|
34
|
+
* user explicitly opts in. Keeping the two apart is the whole point: a startup
|
|
35
|
+
* path that slurped the file "just in case" would make the opt-in decorative.
|
|
36
|
+
*
|
|
37
|
+
* ---------------------------------------------------------------------------
|
|
38
|
+
* RULE 3 — AN ADOPTED CREDENTIAL IS A SNAPSHOT, AND THIS PLUGIN NEVER REFRESHES IT
|
|
39
|
+
* ---------------------------------------------------------------------------
|
|
40
|
+
* An adopted credential is used only while its own accessToken is still valid.
|
|
41
|
+
* Once it is expired the pool reports it as expired and tells the user to sign in
|
|
42
|
+
* again in the Codex CLI and re-adopt. That is deliberate, not a gap: the
|
|
43
|
+
* ChatGPT refresh token the CLI stores ROTATES, and the CLI refreshes its own
|
|
44
|
+
* file in place. Two processes refreshing the same grant therefore invalidate
|
|
45
|
+
* each other — whoever loses the race holds a token the server has already
|
|
46
|
+
* retired, and the user ends up signed OUT of the Codex CLI by this plugin's good
|
|
47
|
+
* intentions. An in-process single-flight cannot fix that, because the race is
|
|
48
|
+
* across PROCESSES: this plugin and the CLI are separate programs with separate
|
|
49
|
+
* memories, and the only shared state between them is the file — which this
|
|
50
|
+
* module must not write back into (Rule 1).
|
|
51
|
+
*
|
|
52
|
+
* So the honest contract is: borrow the access token for as long as the CLI itself
|
|
53
|
+
* vouched for it, and never touch the refresh token. Expiry is therefore part of
|
|
54
|
+
* the adoption decision rather than a detail — see
|
|
55
|
+
* {@link isAdoptedCodexCredentialExpired}.
|
|
56
|
+
*
|
|
57
|
+
* The marker the pool chunk must honour is the literal 'adopted: true' plus
|
|
58
|
+
* {@link isAdoptedCodexCredential}; an account carrying it must be treated as
|
|
59
|
+
* read-only, non-refreshable and disposable. There is deliberately no refresh
|
|
60
|
+
* function in this module to find in the first place.
|
|
61
|
+
*
|
|
62
|
+
* ---------------------------------------------------------------------------
|
|
63
|
+
* RULE 4 — AN UNRECOGNISED SHAPE YIELDS undefined, NEVER AN EXCEPTION
|
|
64
|
+
* ---------------------------------------------------------------------------
|
|
65
|
+
* The card shows 'unrecognised local sign-in format' for undefined, which is a far
|
|
66
|
+
* better outcome than a thrown error escaping into the settings route. Nothing is
|
|
67
|
+
* guessed: a document in another auth_mode, a missing or non-object tokens
|
|
68
|
+
* block, a missing access or refresh token, an access token that is not a JWT
|
|
69
|
+
* with a usable 'exp', an unreadable or unparsable file — all of them are
|
|
70
|
+
* undefined. Extra and unknown fields are ignored rather than rejected, so a
|
|
71
|
+
* future CLI that adds one does not break adoption.
|
|
72
|
+
*
|
|
73
|
+
* THE TRAP THIS PARSER EXISTS TO AVOID. A Codex auth.json is NOT a flat bag of
|
|
74
|
+
* tokens. It is a document that may carry an API key alongside the OAuth tokens,
|
|
75
|
+
* and a "find the first accessToken anywhere in the JSON" scan would pick
|
|
76
|
+
* whichever one the serializer happened to emit first — which is how an API key
|
|
77
|
+
* or an unrelated token ends up presented to the Responses API as the user's
|
|
78
|
+
* subscription credential. The read is therefore a direct, specific lookup of
|
|
79
|
+
* tokens.access_token and its siblings — never a tree walk — and the test suite
|
|
80
|
+
* holds a fixture carrying an unrelated token beside the real one and asserts
|
|
81
|
+
* which comes back.
|
|
82
|
+
*
|
|
83
|
+
* ---------------------------------------------------------------------------
|
|
84
|
+
* THE CLAIMS ARE DERIVED LOCALLY, NEVER ASKED OF ANYBODY
|
|
85
|
+
* ---------------------------------------------------------------------------
|
|
86
|
+
* expiresAt comes from the access token's own 'exp' claim, email and planType
|
|
87
|
+
* from the id token's claims. The JWT payload is decoded in process; no token is
|
|
88
|
+
* ever sent anywhere to be inspected, and no token value is logged or returned
|
|
89
|
+
* from anything but the credential object the caller asked for.
|
|
90
|
+
*
|
|
91
|
+
* WHY EXPIRY IS REFUSED RATHER THAN DEFAULTED. A snapshot whose validity cannot
|
|
92
|
+
* be established must not be used. Rather than stamping "now" or "never" and
|
|
93
|
+
* hoping, this module yields undefined: the card then says the local sign-in
|
|
94
|
+
* format is unrecognised, which is true, instead of importing a credential that
|
|
95
|
+
* would 401 on the first request.
|
|
96
|
+
*/
|
|
97
|
+
import type { StoredOAuthCredentials } from './token-store.ts';
|
|
98
|
+
/**
|
|
99
|
+
* Environment variable that relocates the Codex CLI's home directory.
|
|
100
|
+
*
|
|
101
|
+
* Highest precedence, and honoured exactly as the CLI honours it: when it is set
|
|
102
|
+
* to a non-blank value it names the home that holds auth.json, whatever the
|
|
103
|
+
* platform's conventional location happens to be. This is also what makes the
|
|
104
|
+
* whole module testable without touching a developer's real profile.
|
|
105
|
+
*/
|
|
106
|
+
export declare const CODEX_HOME_ENV = "CODEX_HOME";
|
|
107
|
+
/** File name of the credential document inside the Codex home. */
|
|
108
|
+
export declare const CODEX_CLI_CREDENTIAL_FILE = "auth.json";
|
|
109
|
+
/**
|
|
110
|
+
* Top-level key holding the OAuth tokens.
|
|
111
|
+
*
|
|
112
|
+
* Named as a constant because the specificity of this key IS the defence
|
|
113
|
+
* described in the module comment: the read addresses this key, not the first
|
|
114
|
+
* token it can find anywhere in the document.
|
|
115
|
+
*/
|
|
116
|
+
export declare const CODEX_CLI_TOKENS_KEY = "tokens";
|
|
117
|
+
/**
|
|
118
|
+
* The one auth_mode this provider can adopt.
|
|
119
|
+
*
|
|
120
|
+
* A Codex home may also hold an API-key sign-in, which is a different kind of
|
|
121
|
+
* credential for a different billing arrangement. Adopting it as a subscription
|
|
122
|
+
* sign-in would present the wrong credential to the Responses API, so the mode is
|
|
123
|
+
* checked rather than assumed: an unrecognised mode is an unrecognised document.
|
|
124
|
+
*/
|
|
125
|
+
export declare const CODEX_CLI_CHATGPT_AUTH_MODE = "chatgpt";
|
|
126
|
+
/** Where an adopted snapshot came from, for the card and for the pool record. */
|
|
127
|
+
export declare const CODEX_CLI_CREDENTIAL_SOURCE = "codex";
|
|
128
|
+
/**
|
|
129
|
+
* What the user is told when an adopted credential has aged out.
|
|
130
|
+
*
|
|
131
|
+
* Exported so the pool report and the settings card say the same sentence, and
|
|
132
|
+
* so the instruction is stated once: the re-sign-in happens in the CODEX CLI, not
|
|
133
|
+
* here, and the import has to be repeated afterwards.
|
|
134
|
+
*/
|
|
135
|
+
export declare const ADOPTED_CODEX_CREDENTIAL_EXPIRED_HINT: string;
|
|
136
|
+
/** One adopted credential: the store's own credential shape plus its provenance. */
|
|
137
|
+
export interface CodexCliAdoptedCredential {
|
|
138
|
+
/**
|
|
139
|
+
* The pool marker. Literal true on every snapshot this module returns.
|
|
140
|
+
*
|
|
141
|
+
* A discriminant rather than a description: a pool chunk that stores this record
|
|
142
|
+
* must refuse to refresh it, and a boolean it can test is harder to overlook
|
|
143
|
+
* than a comment it can read past.
|
|
144
|
+
*/
|
|
145
|
+
readonly adopted: true;
|
|
146
|
+
/** Which local sign-in this was taken from. */
|
|
147
|
+
readonly source: typeof CODEX_CLI_CREDENTIAL_SOURCE;
|
|
148
|
+
/** The exact file it was read from, so the card can name it. */
|
|
149
|
+
readonly sourcePath: string;
|
|
150
|
+
/** The credential in the store's own shape, ready to be persisted by the caller. */
|
|
151
|
+
readonly credentials: StoredOAuthCredentials;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The Codex CLI's home directory.
|
|
155
|
+
*
|
|
156
|
+
* The environment override wins whenever it is set to a non-blank value — a blank
|
|
157
|
+
* or whitespace-only variable is treated as unset rather than as "the directory
|
|
158
|
+
* whose name is empty", which on Windows would resolve to a drive-relative path.
|
|
159
|
+
* Otherwise the conventional home/.codex directory is used, os.homedir() being
|
|
160
|
+
* the same %USERPROFILE% on Windows and ~ on POSIX that the CLI itself uses.
|
|
161
|
+
*
|
|
162
|
+
* Read at CALL time rather than captured in a module constant: a test (or an
|
|
163
|
+
* embedder) that sets the variable after import must see the change.
|
|
164
|
+
*/
|
|
165
|
+
export declare function codexHomeDir(): string;
|
|
166
|
+
/**
|
|
167
|
+
* Every path this module will look at, most authoritative first.
|
|
168
|
+
*
|
|
169
|
+
* A single candidate, which is a judgement call stated plainly. The Claude reader
|
|
170
|
+
* in this package also falls back to the conventional home when the environment
|
|
171
|
+
* override points somewhere else; here the override IS the user's own statement of
|
|
172
|
+
* where this CLI keeps its sign-in, and honouring a stale scratch directory is
|
|
173
|
+
* more dangerous than reporting nothing: a snapshot belonging to a profile the CLI
|
|
174
|
+
* is not currently using would be adopted silently. The path actually consulted is
|
|
175
|
+
* returned and printed by the caller, so "not found" is always accompanied by the
|
|
176
|
+
* exact place that was looked at.
|
|
177
|
+
*
|
|
178
|
+
* A pure function — no filesystem access at all — so it is safe to call just to
|
|
179
|
+
* render the card, and so its precedence is testable without touching a disk.
|
|
180
|
+
*/
|
|
181
|
+
export declare function codexCliCredentialPaths(): readonly string[];
|
|
182
|
+
/**
|
|
183
|
+
* Is there a local Codex CLI sign-in to offer?
|
|
184
|
+
*
|
|
185
|
+
* Safe on plugin startup: this NEVER opens a candidate for reading, so a user who
|
|
186
|
+
* never opts in never has the credential's contents touched — not by this
|
|
187
|
+
* function, not by the route that renders the card. Only stat runs, which reveals
|
|
188
|
+
* existence and timestamps and nothing else.
|
|
189
|
+
*
|
|
190
|
+
* Deliberately NOT reported here: whether the file is valid, expired, or even
|
|
191
|
+
* JSON. Answering that would require the read this function exists to avoid, and
|
|
192
|
+
* the card does not need it — validity is answered by the read, after opt-in, and
|
|
193
|
+
* lands on the card as either a credential or 'unrecognised local sign-in
|
|
194
|
+
* format'.
|
|
195
|
+
*
|
|
196
|
+
* A boolean, rather than the record the Claude reader returns, because the two
|
|
197
|
+
* callers want different things and neither needs the other's shape: the status
|
|
198
|
+
* route wants a flag, and reports the path it consulted beside it. paths
|
|
199
|
+
* is injectable so tests drive it against fixtures instead of a real profile;
|
|
200
|
+
* production callers take the default.
|
|
201
|
+
*/
|
|
202
|
+
export declare function codexCliCredentialPresence(paths?: readonly string[]): Promise<boolean>;
|
|
203
|
+
/**
|
|
204
|
+
* Map one parsed credential document onto the store's credential shape.
|
|
205
|
+
*
|
|
206
|
+
* Pure and exported so the format rules can be tested without a filesystem, and
|
|
207
|
+
* so a later chunk that reads the document from somewhere else (a backup, a pasted
|
|
208
|
+
* blob) reuses the one set of rules instead of growing a second, drifting copy.
|
|
209
|
+
*
|
|
210
|
+
* Returns undefined for every shape it does not recognise, and never throws — see
|
|
211
|
+
* Rule 4 in the module comment. The gate is deliberately narrow: the document must
|
|
212
|
+
* be a JSON object in the ChatGPT auth mode, its tokens block must be an object,
|
|
213
|
+
* and it must carry BOTH a non-empty access token and a non-empty refresh token.
|
|
214
|
+
* An access token alone is not adopted because the store's record is a sign-in,
|
|
215
|
+
* not a bare token, and a record with an empty one could never be re-recognised.
|
|
216
|
+
*
|
|
217
|
+
* The unrelated-token trap is handled by construction: value.tokens is addressed
|
|
218
|
+
* directly and no other key of the document is ever traversed, so whatever else
|
|
219
|
+
* the file carries cannot reach the result.
|
|
220
|
+
*/
|
|
221
|
+
export declare function parseAdoptedCodexCredential(value: unknown, sourcePath: string): CodexCliAdoptedCredential | undefined;
|
|
222
|
+
/**
|
|
223
|
+
* Read the local Codex CLI sign-in; the first usable candidate wins.
|
|
224
|
+
*
|
|
225
|
+
* ONLY call this after the user has explicitly opted in — see the module comment.
|
|
226
|
+
*
|
|
227
|
+
* Never throws and never rejects: an absent file, an unreadable file, a file that
|
|
228
|
+
* is not JSON, and a JSON document of an unrecognised shape all produce undefined,
|
|
229
|
+
* which the card renders as 'unrecognised local sign-in format'. A settings route
|
|
230
|
+
* must not be able to fail because a user's file was mid-write.
|
|
231
|
+
*/
|
|
232
|
+
export declare function readCodexCliCredentials(paths?: readonly string[]): Promise<CodexCliAdoptedCredential | undefined>;
|
|
233
|
+
/**
|
|
234
|
+
* Whether a value carries the adopted marker.
|
|
235
|
+
*
|
|
236
|
+
* The predicate the pool chunk tests a stored credential with before deciding
|
|
237
|
+
* whether it may ever be refreshed. It recognises this module's snapshot and
|
|
238
|
+
* nothing else: a plain store credential has no 'adopted' field and must NOT be
|
|
239
|
+
* mistaken for one, because treating a plugin-owned account as a disposable
|
|
240
|
+
* snapshot would freeze an account the user signed in here.
|
|
241
|
+
*/
|
|
242
|
+
export declare function isAdoptedCodexCredential(value: unknown): value is CodexCliAdoptedCredential;
|
|
243
|
+
/**
|
|
244
|
+
* Whether an adopted credential's access token is already unusable.
|
|
245
|
+
*
|
|
246
|
+
* A structural mirror of the expiry test the OAuth module applies to its own
|
|
247
|
+
* credentials (expiresAt - Date.now() > 0), asked of a pooled credential so the
|
|
248
|
+
* pool can refuse it WITHOUT ever reaching for a refresh this module deliberately
|
|
249
|
+
* does not perform. A non-finite expiresAt counts as expired, matching the
|
|
250
|
+
* refusal in the reader: no established validity, no use.
|
|
251
|
+
*
|
|
252
|
+
* now is injectable so a test can reason about a fixed clock.
|
|
253
|
+
*/
|
|
254
|
+
export declare function isAdoptedCodexCredentialExpired(credential: Pick<StoredOAuthCredentials, 'expiresAt'>, now?: number): boolean;
|
|
255
|
+
//# sourceMappingURL=codex-adopt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-adopt.d.ts","sourceRoot":"","sources":["../../../src/host/codex-adopt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+FG;AAUH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAE9D;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,eAAe,CAAA;AAE1C,kEAAkE;AAClE,eAAO,MAAM,yBAAyB,cAAc,CAAA;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,WAAW,CAAA;AAE5C;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,YAAY,CAAA;AAEpD,iFAAiF;AACjF,eAAO,MAAM,2BAA2B,UAAU,CAAA;AAKlD;;;;;;GAMG;AACH,eAAO,MAAM,qCAAqC,QAEM,CAAA;AAExD,oFAAoF;AACpF,MAAM,WAAW,yBAAyB;IACxC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAA;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,OAAO,2BAA2B,CAAA;IACnD,gEAAgE;IAChE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,oFAAoF;IACpF,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAA;CAC7C;AAaD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAIrC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,IAAI,SAAS,MAAM,EAAE,CAE3D;AAqBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,GAAE,SAAS,MAAM,EAA8B,GACnD,OAAO,CAAC,OAAO,CAAC,CAKlB;AA8CD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,EACd,UAAU,EAAE,MAAM,GACjB,yBAAyB,GAAG,SAAS,CA2CvC;AAED;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,KAAK,GAAE,SAAS,MAAM,EAA8B,GACnD,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC,CAchD;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,yBAAyB,CAK3F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAC7C,UAAU,EAAE,IAAI,CAAC,sBAAsB,EAAE,WAAW,CAAC,EACrD,GAAG,GAAE,MAAmB,GACvB,OAAO,CAGT"}
|
|
@@ -12,6 +12,22 @@
|
|
|
12
12
|
* degenerate stream scores near one. On a hit it stops yielding chunks, so the
|
|
13
13
|
* in-flight request ends, and lets the turn resume on a fresh step.
|
|
14
14
|
*
|
|
15
|
+
* Uniqueness alone only sees verbatim repetition. A stream can restate one
|
|
16
|
+
* conclusion over and over in fresh words, score 0.48 where the threshold is
|
|
17
|
+
* 0.85, and run to the output ceiling untouched. So a second, independent
|
|
18
|
+
* signal scores the same window for recurrence: how strongly each sentence
|
|
19
|
+
* repeats something the model already said at least `semanticLag` sentences
|
|
20
|
+
* earlier. Enumerative reasoning repeats itself too, but adjacently — each item
|
|
21
|
+
* borrows the previous item's frame — and recurrence ignores adjacency, which
|
|
22
|
+
* is what separates the two.
|
|
23
|
+
*
|
|
24
|
+
* Neither signal stops anything on its own. A break needs both over their
|
|
25
|
+
* thresholds in the same window, and then `semanticConfirmations` consecutive
|
|
26
|
+
* such windows: one signal alone, or a single anomalous window, is logged and
|
|
27
|
+
* released. That gradient is the whole design. A guard that cuts a healthy
|
|
28
|
+
* answer is worse than one that lets a runaway finish, because the user sees a
|
|
29
|
+
* turn stop mid-sentence with no explanation, and the fix costs a whole turn.
|
|
30
|
+
*
|
|
15
31
|
* Seam choice: the guard wraps `llm/stream`, not `agent/assistant-stream`.
|
|
16
32
|
* `agent/assistant-stream` is emit-mode — it can observe but cannot stop a
|
|
17
33
|
* stream — and it does not exist before harness 0.1.5, which would make the
|
|
@@ -120,6 +136,91 @@ export interface GuardOptions {
|
|
|
120
136
|
cooldownMs?: number;
|
|
121
137
|
/** Model ids to watch; empty watches every model. */
|
|
122
138
|
includeModels?: string[];
|
|
139
|
+
/**
|
|
140
|
+
* Recurrence score at or above which the semantic signal is considered to
|
|
141
|
+
* hold (default 0.35).
|
|
142
|
+
*
|
|
143
|
+
* Measured on the trailing window: the three healthy fixtures peak at 0.19,
|
|
144
|
+
* 0.17 and 0.17 across every streaming prefix, while a paraphrased loop and
|
|
145
|
+
* the verbatim loop score 0.75 and 0.99. 0.35 sits near the geometric mean
|
|
146
|
+
* of that gap, roughly 1.8x above the worst healthy prefix.
|
|
147
|
+
*/
|
|
148
|
+
semanticThreshold?: number;
|
|
149
|
+
/**
|
|
150
|
+
* Sentences a claim must be separated from to count as recurrence
|
|
151
|
+
* (default 6).
|
|
152
|
+
*
|
|
153
|
+
* Zero would make healthy enumeration look degenerate: item N of a list
|
|
154
|
+
* legitimately shares most of its wording with item N-1. Requiring the
|
|
155
|
+
* earlier sentence to be at least this far back keeps the measurement on
|
|
156
|
+
* "the model said this before" rather than "the model is still on this point".
|
|
157
|
+
*/
|
|
158
|
+
semanticLag?: number;
|
|
159
|
+
/**
|
|
160
|
+
* Characters required before the semantic signal is scored (default 360).
|
|
161
|
+
*
|
|
162
|
+
* Deliberately its own floor, well below `minWindowChars`: a real trace
|
|
163
|
+
* emitted 16 steps of which only one crossed 1500 characters, so the
|
|
164
|
+
* literal signal saw a single step of a whole turn. The two floors are
|
|
165
|
+
* separate knobs because they answer different questions — the literal one
|
|
166
|
+
* is about how much text a duplicate needs to be visible in, the semantic
|
|
167
|
+
* one about how much text a recurrence needs to be measurable in.
|
|
168
|
+
*/
|
|
169
|
+
semanticMinChars?: number;
|
|
170
|
+
/** Sentences required before recurrence is scored (default 8). */
|
|
171
|
+
semanticMinSentences?: number;
|
|
172
|
+
/**
|
|
173
|
+
* Consecutive windows in which both signals must hold before a break
|
|
174
|
+
* (default 3).
|
|
175
|
+
*
|
|
176
|
+
* Counted independently of the per-turn break budget, which bounds how often
|
|
177
|
+
* the guard may act, not how sure it must be. A stream delivers a scoring
|
|
178
|
+
* window every few dozen characters, so three confirmations cost a few
|
|
179
|
+
* hundred wasted tokens against a runaway measured in the tens of thousands.
|
|
180
|
+
*/
|
|
181
|
+
semanticConfirmations?: number;
|
|
182
|
+
/**
|
|
183
|
+
* Lowest literal score the low-literal path will act on (default 0.6).
|
|
184
|
+
*
|
|
185
|
+
* A paraphrased loop sits far below `threshold` — measured at 0.676 for a
|
|
186
|
+
* model restating twelve conclusions in fresh words, against 0.85 for
|
|
187
|
+
* verbatim repetition. So a strong semantic signal has to be allowed to
|
|
188
|
+
* carry a decision the literal signal cannot make on its own.
|
|
189
|
+
*
|
|
190
|
+
* The floor exists because a low score is not the same as a high one: 0.6 is
|
|
191
|
+
* evidence that something is repeating, 0.2 is a short trace that has not
|
|
192
|
+
* repeated long enough to say anything. Measured healthy literal peaks at
|
|
193
|
+
* 0.276, so 0.6 keeps a 2.2x margin over every healthy prefix.
|
|
194
|
+
*/
|
|
195
|
+
semanticLiteralFloor?: number;
|
|
196
|
+
/**
|
|
197
|
+
* Semantic score the low-literal path demands (default 0.45).
|
|
198
|
+
*
|
|
199
|
+
* Strictly greater than `semanticThreshold`, and validated as such. The literal
|
|
200
|
+
* evidence on this path is weaker by construction, so the semantic evidence
|
|
201
|
+
* has to be stronger: 0.45 against a measured healthy peak of 0.194 is a
|
|
202
|
+
* 2.3x margin, while a paraphrase loop measures 0.77.
|
|
203
|
+
*/
|
|
204
|
+
semanticStrictThreshold?: number;
|
|
205
|
+
/**
|
|
206
|
+
* Most of a window's sentences may be distinct and still be eligible for the
|
|
207
|
+
* low-literal path (default 0.47).
|
|
208
|
+
*
|
|
209
|
+
* This is the dimension that separates a model circling from a model
|
|
210
|
+
* listing. Both reuse a frame heavily and both score high on recurrence, but
|
|
211
|
+
* a list writes a sentence that has never been written before on every line
|
|
212
|
+
* — measured at 1.000 distinct, against 0.42 for a paraphrase loop and 0.075
|
|
213
|
+
* for a verbatim one. Recurrence says the wording comes back; this says
|
|
214
|
+
* whether anything at all was new.
|
|
215
|
+
*/
|
|
216
|
+
semanticDistinctCeiling?: number;
|
|
217
|
+
/**
|
|
218
|
+
* Consecutive windows the low-literal path needs (default 5).
|
|
219
|
+
*
|
|
220
|
+
* Strictly greater than `semanticConfirmations`, and validated as such. The path is
|
|
221
|
+
* acting on weaker evidence, so it also waits longer before it acts.
|
|
222
|
+
*/
|
|
223
|
+
semanticStrictConfirmations?: number;
|
|
123
224
|
/** Injectable clock, so the cooldown is testable without a timer. */
|
|
124
225
|
now?: () => number;
|
|
125
226
|
}
|
|
@@ -132,6 +233,15 @@ export interface ResolvedGuardOptions {
|
|
|
132
233
|
maxBreaksPerTurn: number;
|
|
133
234
|
cooldownMs: number;
|
|
134
235
|
includeModels: string[];
|
|
236
|
+
semanticThreshold: number;
|
|
237
|
+
semanticLag: number;
|
|
238
|
+
semanticMinChars: number;
|
|
239
|
+
semanticMinSentences: number;
|
|
240
|
+
semanticConfirmations: number;
|
|
241
|
+
semanticLiteralFloor: number;
|
|
242
|
+
semanticStrictThreshold: number;
|
|
243
|
+
semanticDistinctCeiling: number;
|
|
244
|
+
semanticStrictConfirmations: number;
|
|
135
245
|
now: () => number;
|
|
136
246
|
}
|
|
137
247
|
export declare const DEFAULT_GUARD_OPTIONS: ResolvedGuardOptions;
|
|
@@ -151,6 +261,62 @@ export declare function resolveGuardOptions(options?: GuardOptions): ResolvedGua
|
|
|
151
261
|
* @returns collapse score in [0,1]; 0 means every n-gram is unique.
|
|
152
262
|
*/
|
|
153
263
|
export declare function collapseScore(window: string, n: number): number;
|
|
264
|
+
/**
|
|
265
|
+
* Split reasoning text into sentences, for mixed CJK and Latin streams.
|
|
266
|
+
*
|
|
267
|
+
* A Chinese full stop ends a sentence whatever follows it. An ASCII `.!?` only
|
|
268
|
+
* ends one when whitespace or the end of the text follows, because the same
|
|
269
|
+
* characters carry out decimals, file names and version numbers
|
|
270
|
+
* (`selectors.test.ts:745`, `3.14`) that must not become sentence
|
|
271
|
+
* edges. Whitespace runs collapse and case folds, so a difference in spacing
|
|
272
|
+
* or capitalisation cannot read as a difference in wording.
|
|
273
|
+
*
|
|
274
|
+
* @param text - reasoning text, typically one trailing window.
|
|
275
|
+
* @returns non-empty normalized sentences, in order.
|
|
276
|
+
*/
|
|
277
|
+
export declare function splitSentences(text: string): string[];
|
|
278
|
+
/**
|
|
279
|
+
* How strongly a window keeps returning to sentences it already stated.
|
|
280
|
+
*
|
|
281
|
+
* Each sentence is compared against every sentence at least `lag` positions earlier
|
|
282
|
+
* and keeps the best match; the score is the mean of those best matches. The
|
|
283
|
+
* comparison is normalized (Jaccard), so two sentences match on shared wording
|
|
284
|
+
* rather than on shared length, and character n-grams are used rather than words
|
|
285
|
+
* because no tokenizer is available here, and none would survive a CJK/Latin
|
|
286
|
+
* mix without segmenting Chinese first.
|
|
287
|
+
*
|
|
288
|
+
* Two properties matter more than the exact number. The score saturates — a
|
|
289
|
+
* twelve-sentence loop and a four-hundred-sentence one both approach one — so
|
|
290
|
+
* it does not drift with length the way a mean pairwise similarity does, and
|
|
291
|
+
* it does not reward a long answer merely for containing more pairs. And the
|
|
292
|
+
* lag is what makes it safe to ship: healthy enumeration reuses its framing
|
|
293
|
+
* from the sentence immediately before, which this metric cannot see.
|
|
294
|
+
*
|
|
295
|
+
* @param window - trailing reasoning characters.
|
|
296
|
+
* @param lag - sentences a claim must be separated from to count as recurrence.
|
|
297
|
+
* @returns recurrence score in [0,1]; 0 means nothing recurs, or too little text to tell.
|
|
298
|
+
*/
|
|
299
|
+
export declare function semanticRecurrence(window: string, lag: number): number;
|
|
300
|
+
/**
|
|
301
|
+
* The share of a window's sentences that have never been said before.
|
|
302
|
+
*
|
|
303
|
+
* Recurrence cannot tell a model that is circling from a model that is
|
|
304
|
+
* listing, because a list reuses its frame as heavily as a loop does and
|
|
305
|
+
* scores just as high. The difference is that a list writes a new sentence on
|
|
306
|
+
* every line. Measured over a trailing window: 0.075 for the verbatim loop,
|
|
307
|
+
* 0.42 for a paraphrase loop, 1.000 for every healthy fixture and for every
|
|
308
|
+
* list shape tried.
|
|
309
|
+
*
|
|
310
|
+
* Equality is exact and on the normalized sentence, which is what keeps the
|
|
311
|
+
* lists out. Two rows differing only by a row number are 0.86 similar by
|
|
312
|
+
* `semanticRecurrence` and 1.000 distinct here, and that gap is the whole point: the
|
|
313
|
+
* fuzzy measure asks whether the wording came back, this one asks whether
|
|
314
|
+
* anything was new.
|
|
315
|
+
*
|
|
316
|
+
* @param window - trailing reasoning characters.
|
|
317
|
+
* @returns distinct share in (0,1]; 1 when every sentence is unique.
|
|
318
|
+
*/
|
|
319
|
+
export declare function distinctSentenceRatio(window: string): number;
|
|
154
320
|
export declare const RESUME_HINT: string;
|
|
155
321
|
/** The second resume message, used once a resume has also collapsed. */
|
|
156
322
|
export declare const RESUME_HINT_STRICT: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/host/reasoning-collapse-guard/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/host/reasoning-collapse-guard/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,5 +8,15 @@ import type { SearchProviderSwitcher } from './search-provider-switcher.ts';
|
|
|
8
8
|
import { UsageService } from './usage-service.ts';
|
|
9
9
|
/** Read-only audit provider the optional route serves. */
|
|
10
10
|
export type RouteAuditReader = (sessionId: string) => Promise<SubagentRouteAuditDto>;
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Test seam for the adopt routes: the paths the Codex reader consults.
|
|
13
|
+
*
|
|
14
|
+
* Present for the same reason the Claude line carries 'adoptPaths': the reader
|
|
15
|
+
* resolves its own path from CODEX_HOME, and a test must point it at a fixture
|
|
16
|
+
* rather than at the machine it is running on. Production callers take the default.
|
|
17
|
+
*/
|
|
18
|
+
export interface RouteAdoptOptions {
|
|
19
|
+
adoptPaths?: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
export declare function registerRoutes(ctx: Context, oauth: OAuthService, usage: UsageService, preferences: SubscriptionPreferenceStore, proxyManager?: ProxyManager, searchSwitcher?: SearchProviderSwitcher, routeAudit?: RouteAuditReader, accountPool?: CodexAccountPool, fetchConfiguration?: FetchConfigurationDto, adopt?: RouteAdoptOptions): () => void;
|
|
12
22
|
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/host/routes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,KAAK,EAEV,qBAAqB,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/host/routes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,KAAK,EAEV,qBAAqB,EAIrB,qBAAqB,EAEtB,MAAM,wBAAwB,CAAA;AAG/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE/D,OAAO,EAAE,YAAY,EAAe,MAAM,oBAAoB,CAAA;AAC9D,OAAO,EAAmB,KAAK,2BAA2B,EAAE,MAAM,kBAAkB,CAAA;AACpF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AAC3E,OAAO,EAAE,YAAY,EAAqB,MAAM,oBAAoB,CAAA;AAKpE,0DAA0D;AAC1D,MAAM,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;AAEpF;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC/B;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,2BAA2B,EACxC,YAAY,CAAC,EAAE,YAAY,EAC3B,cAAc,CAAC,EAAE,sBAAsB,EACvC,UAAU,CAAC,EAAE,gBAAgB,EAC7B,WAAW,CAAC,EAAE,gBAAgB,EAC9B,kBAAkB,CAAC,EAAE,qBAAqB,EAC1C,KAAK,CAAC,EAAE,iBAAiB,GACxB,MAAM,IAAI,CAwUZ"}
|
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
import type { CredentialStorageDto } from '../shared/contracts.ts';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* The adoption markers, as they hang off a credential this package stores.
|
|
4
|
+
*
|
|
5
|
+
* FLATTENED onto the credential rather than nested under it, for the same reason
|
|
6
|
+
* the Claude line flattens its own: the pool's hooks (needsRefresh, refresh,
|
|
7
|
+
* authRejectedReason) receive the CREDENTIAL and never the account record, so the
|
|
8
|
+
* marker has to be reachable from there, and every other field a pooled row reads
|
|
9
|
+
* already sits at the top level.
|
|
10
|
+
*
|
|
11
|
+
* A borrowed snapshot is never refreshed (the refresh token belongs to the client
|
|
12
|
+
* that wrote the file, and two programs spending it invalidate each other), so the
|
|
13
|
+
* marker is the whole difference between a row this plugin may rotate and a row
|
|
14
|
+
* that is a snapshot until it expires. It is written on EVERY account the pool
|
|
15
|
+
* creates, including the explicit false case, because the core merges a
|
|
16
|
+
* re-authorization as { ...existing, ...created } and an omitted key would leave a
|
|
17
|
+
* stored 'adopted: true' behind.
|
|
18
|
+
*/
|
|
19
|
+
export interface AdoptedCredentialMarkers {
|
|
20
|
+
/** Literal true on a credential copied out of another application's sign-in. */
|
|
21
|
+
adopted?: true;
|
|
22
|
+
/** Which local sign-in it was taken from, e.g. 'codex'. */
|
|
23
|
+
source?: string;
|
|
24
|
+
/** The exact file it was read from, so a card can name it. */
|
|
25
|
+
sourcePath?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface StoredOAuthCredentials extends AdoptedCredentialMarkers {
|
|
3
28
|
accessToken: string;
|
|
4
29
|
refreshToken: string;
|
|
5
30
|
idToken?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-store.d.ts","sourceRoot":"","sources":["../../../src/host/token-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAElE,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"token-store.d.ts","sourceRoot":"","sources":["../../../src/host/token-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAElE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,wBAAwB;IACvC,gFAAgF;IAChF,OAAO,CAAC,EAAE,IAAI,CAAA;IACd,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,sBAAuB,SAAQ,wBAAwB;IACtE,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC;IAChC,IAAI,IAAI,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IACzB,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAED,MAAM,WAAW,UAAW,SAAQ,eAAe,CAAC,sBAAsB,CAAC;IACzE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAA;CAC1D;AAED,6EAA6E;AAC7E,qBAAa,gBAAiB,YAAW,UAAU;IACjD,QAAQ,CAAC,OAAO;;;MAAgD;IAChE,OAAO,CAAC,KAAK,CAAsC;IAE7C,IAAI,IAAI,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC;IAI9C,IAAI,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,sBAAsB,CAoC7E"}
|
|
@@ -2,7 +2,7 @@ import type { WorkBuddyAccount, WorkBuddyAccountQuota, WorkBuddyMeter } from '..
|
|
|
2
2
|
import { PROVIDER_ID, PROVIDER_NAME } from './types.ts';
|
|
3
3
|
import { FileCredentialStore, type WorkBuddyCredentials } from './token-store.ts';
|
|
4
4
|
import type { WorkBuddyTokenIdentity } from './identity.ts';
|
|
5
|
-
import type
|
|
5
|
+
import { type WorkBuddyModelEntry } from './model-catalog.ts';
|
|
6
6
|
export interface WorkBuddyRequestOptions {
|
|
7
7
|
fetchFn?: typeof fetch;
|
|
8
8
|
signal?: AbortSignal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/host/workbuddy/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,qBAAqB,EACrB,cAAc,EACf,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EAiBL,WAAW,EACX,aAAa,EAKd,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,mBAAmB,EAAsB,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACrG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAC3D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/host/workbuddy/client.ts"],"names":[],"mappings":"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"}
|