@eddyskywalker/dsh-chatgpt-subscription 0.1.4 → 0.1.6
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 +37 -40
- package/README.md +30 -15
- package/lib/client.js +34 -250
- package/lib/client.js.map +1 -1
- package/lib/index.js +271 -16
- package/lib/types/client/CodexSubscriptionSection.d.ts +3 -1
- package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +17 -5
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/styles.d.ts.map +1 -1
- package/lib/types/host/oauth-service.d.ts.map +1 -1
- package/lib/types/host/platform-token-store.d.ts +3 -0
- package/lib/types/host/platform-token-store.d.ts.map +1 -0
- package/lib/types/host/subagent-report-scheduling-compat.d.ts +21 -0
- package/lib/types/host/subagent-report-scheduling-compat.d.ts.map +1 -0
- package/lib/types/host/token-store-linux.d.ts +20 -0
- package/lib/types/host/token-store-linux.d.ts.map +1 -0
- package/lib/types/host/token-store-windows.d.ts +4 -0
- package/lib/types/host/token-store-windows.d.ts.map +1 -1
- package/lib/types/host/token-store.d.ts +6 -0
- package/lib/types/host/token-store.d.ts.map +1 -1
- package/lib/types/index.d.ts +3 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/contracts.d.ts +7 -4
- package/lib/types/shared/contracts.d.ts.map +1 -1
- package/package.json +107 -105
- package/lib/types/client/process-folding.d.ts +0 -5
- package/lib/types/client/process-folding.d.ts.map +0 -1
package/lib/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { CallId, LlmAdapter, LlmError, ProviderRequestId, ReasoningEffortId, attributionHeaders, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
|
|
2
2
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
3
3
|
import http from "node:http";
|
|
4
|
+
import { constants } from "node:fs";
|
|
5
|
+
import { chmod, lstat, mkdir, open, rename, stat, unlink } from "node:fs/promises";
|
|
4
6
|
import { homedir } from "node:os";
|
|
5
7
|
import { dirname, join } from "node:path";
|
|
6
8
|
import { spawn } from "node:child_process";
|
|
@@ -122,6 +124,141 @@ var CodexChatGptAdapter = class extends LlmAdapter {
|
|
|
122
124
|
}
|
|
123
125
|
};
|
|
124
126
|
//#endregion
|
|
127
|
+
//#region src/host/subagent-report-scheduling-compat.ts
|
|
128
|
+
/**
|
|
129
|
+
* DSH_COMPAT_REMOVE(subagent-report-settlement-dedup)
|
|
130
|
+
*
|
|
131
|
+
* Temporary compatibility shim for DSH 0.1.0-rc.6. A continuable child is told
|
|
132
|
+
* to report its result before finishing, while DSH also unconditionally sends
|
|
133
|
+
* the same closing output in a `subagent-settled` notice. The report is often
|
|
134
|
+
* still queued when the settlement reaches the parent, so the parent sees the
|
|
135
|
+
* result once and the equivalent report remains as duplicate next-turn work.
|
|
136
|
+
*
|
|
137
|
+
* Remove this module, its installation in `src/index.ts`, and its focused test
|
|
138
|
+
* once upstream coalesces an equivalent final report with settlement delivery.
|
|
139
|
+
*/
|
|
140
|
+
const DSH_SUBAGENT_REPORT_DEDUP_COMPAT_MARKER = "__dshChatgptSubscriptionSubagentReportDedupCompatV1";
|
|
141
|
+
function sourceOf(message) {
|
|
142
|
+
return message.source;
|
|
143
|
+
}
|
|
144
|
+
function isTextBlock(value, text) {
|
|
145
|
+
return typeof value === "object" && value !== null && value.type === "text" && value.text === text;
|
|
146
|
+
}
|
|
147
|
+
function sameValue(left, right) {
|
|
148
|
+
if (left === right) return true;
|
|
149
|
+
if (Array.isArray(left) || Array.isArray(right)) return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => sameValue(value, right[index]));
|
|
150
|
+
if (typeof left !== "object" || left === null || typeof right !== "object" || right === null) return false;
|
|
151
|
+
const leftRecord = left;
|
|
152
|
+
const rightRecord = right;
|
|
153
|
+
const leftKeys = Object.keys(leftRecord).sort();
|
|
154
|
+
const rightKeys = Object.keys(rightRecord).sort();
|
|
155
|
+
return leftKeys.length === rightKeys.length && leftKeys.every((key, index) => key === rightKeys[index] && sameValue(leftRecord[key], rightRecord[key]));
|
|
156
|
+
}
|
|
157
|
+
function duplicatePendingReports(agent, settlement) {
|
|
158
|
+
const settlementSource = sourceOf(settlement);
|
|
159
|
+
if (settlementSource.kind !== "subagent-settled" || settlementSource.senderSessionId === void 0) return [];
|
|
160
|
+
if (settlement.content.length < 2 || !isTextBlock(settlement.content[1], "Its closing message:")) return [];
|
|
161
|
+
const closingContent = settlement.content.slice(2);
|
|
162
|
+
return [...agent.inbox.nextStep, ...agent.inbox.nextTurn].filter((pending) => {
|
|
163
|
+
const pendingSource = sourceOf(pending);
|
|
164
|
+
return pendingSource.kind === "subagent-report" && pendingSource.senderSessionId === settlementSource.senderSessionId && sameValue(pending.content.slice(1), closingContent);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function errorMessage(error) {
|
|
168
|
+
return error instanceof Error ? error.message : String(error);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Discard only an exact, same-child report duplicate immediately before DSH
|
|
172
|
+
* delivers the corresponding settlement notice. Partial reports, reports with
|
|
173
|
+
* different content, and all unrelated inbox work remain untouched.
|
|
174
|
+
*/
|
|
175
|
+
function installSubagentReportDedupCompat(ctx) {
|
|
176
|
+
const patches = /* @__PURE__ */ new Map();
|
|
177
|
+
const patch = (agent) => {
|
|
178
|
+
if (patches.has(agent)) return;
|
|
179
|
+
const shared = agent.followup[DSH_SUBAGENT_REPORT_DEDUP_COMPAT_MARKER];
|
|
180
|
+
if (shared?.wrappers.followup === agent.followup && shared.wrappers.steer === agent.steer && shared.wrappers.inject === agent.inject) {
|
|
181
|
+
shared.owners += 1;
|
|
182
|
+
patches.set(agent, shared);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const originals = {
|
|
186
|
+
followup: agent.followup,
|
|
187
|
+
steer: agent.steer,
|
|
188
|
+
inject: agent.inject
|
|
189
|
+
};
|
|
190
|
+
let record;
|
|
191
|
+
const deliver = (name, message) => {
|
|
192
|
+
for (const duplicate of duplicatePendingReports(agent, message)) try {
|
|
193
|
+
agent.inbox.remove(duplicate.id);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
ctx.logger.warn("[dsh-chatgpt-subscription] Could not discard a duplicate DSH subagent report: " + errorMessage(error));
|
|
196
|
+
}
|
|
197
|
+
originals[name].call(agent, message);
|
|
198
|
+
};
|
|
199
|
+
const wrappers = {
|
|
200
|
+
followup(message) {
|
|
201
|
+
deliver("followup", message);
|
|
202
|
+
},
|
|
203
|
+
steer(message) {
|
|
204
|
+
deliver("steer", message);
|
|
205
|
+
},
|
|
206
|
+
inject(message) {
|
|
207
|
+
deliver("inject", message);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
record = {
|
|
211
|
+
originals,
|
|
212
|
+
wrappers,
|
|
213
|
+
owners: 1
|
|
214
|
+
};
|
|
215
|
+
for (const wrapper of Object.values(wrappers)) Object.defineProperty(wrapper, DSH_SUBAGENT_REPORT_DEDUP_COMPAT_MARKER, { value: record });
|
|
216
|
+
try {
|
|
217
|
+
agent.followup = wrappers.followup;
|
|
218
|
+
agent.steer = wrappers.steer;
|
|
219
|
+
agent.inject = wrappers.inject;
|
|
220
|
+
patches.set(agent, record);
|
|
221
|
+
} catch (error) {
|
|
222
|
+
record.owners = 0;
|
|
223
|
+
for (const name of [
|
|
224
|
+
"followup",
|
|
225
|
+
"steer",
|
|
226
|
+
"inject"
|
|
227
|
+
]) if (agent[name] === wrappers[name]) try {
|
|
228
|
+
agent[name] = originals[name];
|
|
229
|
+
} catch {}
|
|
230
|
+
ctx.logger.warn("[dsh-chatgpt-subscription] Could not install temporary DSH subagent dedup compatibility: " + errorMessage(error));
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
const unpatch = (agent) => {
|
|
234
|
+
const record = patches.get(agent);
|
|
235
|
+
if (!record) return;
|
|
236
|
+
patches.delete(agent);
|
|
237
|
+
record.owners -= 1;
|
|
238
|
+
if (record.owners > 0) return;
|
|
239
|
+
for (const name of [
|
|
240
|
+
"followup",
|
|
241
|
+
"steer",
|
|
242
|
+
"inject"
|
|
243
|
+
]) {
|
|
244
|
+
if (agent[name] !== record.wrappers[name]) continue;
|
|
245
|
+
try {
|
|
246
|
+
agent[name] = record.originals[name];
|
|
247
|
+
} catch (error) {
|
|
248
|
+
ctx.logger.warn("[dsh-chatgpt-subscription] Could not remove temporary DSH subagent dedup compatibility: " + errorMessage(error));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
for (const agent of ctx.agents.list()) patch(agent);
|
|
253
|
+
const disposeCreated = ctx.on("agent/created", ({ agent }) => patch(agent));
|
|
254
|
+
const disposeDisposed = ctx.on("agent/disposed", ({ agent }) => unpatch(agent));
|
|
255
|
+
return () => {
|
|
256
|
+
disposeDisposed();
|
|
257
|
+
disposeCreated();
|
|
258
|
+
for (const agent of [...patches.keys()]) unpatch(agent);
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
//#endregion
|
|
125
262
|
//#region src/compat.ts
|
|
126
263
|
/**
|
|
127
264
|
* Compatibility constants for the ChatGPT-backed Codex flow. The backend and
|
|
@@ -293,13 +430,16 @@ var OAuthService = class {
|
|
|
293
430
|
return this.statusFromCredentials(credentials);
|
|
294
431
|
} catch {
|
|
295
432
|
return {
|
|
296
|
-
...this.statusFromCredentials(null),
|
|
433
|
+
...this.statusFromCredentials(null, false),
|
|
297
434
|
error: publicError(new OAuthServiceError("storage-failed", "Secure credential storage could not be read."))
|
|
298
435
|
};
|
|
299
436
|
}
|
|
300
437
|
}
|
|
301
438
|
async startLogin() {
|
|
302
439
|
this.assertAvailable();
|
|
440
|
+
await this.store.load().catch(() => {
|
|
441
|
+
throw new OAuthServiceError("storage-failed", "Secure credential storage is unavailable. Fix its ownership or permissions before signing in.");
|
|
442
|
+
});
|
|
303
443
|
if (this.activeLogin !== null) throw new OAuthServiceError("login-active", "A ChatGPT sign-in is already in progress.");
|
|
304
444
|
this.lastLoginError = void 0;
|
|
305
445
|
const loginId = this.random(24).toString("base64url");
|
|
@@ -452,14 +592,14 @@ var OAuthService = class {
|
|
|
452
592
|
if (stored === null) throw new OAuthServiceError("not-authenticated", "Sign in with ChatGPT first.");
|
|
453
593
|
return stored;
|
|
454
594
|
}
|
|
455
|
-
statusFromCredentials(credentials) {
|
|
595
|
+
statusFromCredentials(credentials, storageAvailable = true) {
|
|
456
596
|
const active = this.activeLogin;
|
|
457
597
|
if (credentials === null) return {
|
|
458
598
|
authenticated: false,
|
|
459
599
|
account: null,
|
|
460
600
|
storage: {
|
|
461
|
-
|
|
462
|
-
|
|
601
|
+
...this.store.storage,
|
|
602
|
+
available: storageAvailable
|
|
463
603
|
},
|
|
464
604
|
login: {
|
|
465
605
|
active: active !== null,
|
|
@@ -478,8 +618,8 @@ var OAuthService = class {
|
|
|
478
618
|
tokenExpiresAt: Math.floor(credentials.expiresAt / 1e3)
|
|
479
619
|
},
|
|
480
620
|
storage: {
|
|
481
|
-
|
|
482
|
-
|
|
621
|
+
...this.store.storage,
|
|
622
|
+
available: storageAvailable
|
|
483
623
|
},
|
|
484
624
|
login: {
|
|
485
625
|
active: active !== null,
|
|
@@ -718,7 +858,7 @@ async function buildResponsesPayload(options, attachments, localRawImages = {})
|
|
|
718
858
|
}
|
|
719
859
|
function runCodeInstruction(tools) {
|
|
720
860
|
if (!tools?.some((tool) => tool.name === "run_code")) return void 0;
|
|
721
|
-
return "run_code compatibility rule: its code is parsed as strict JavaScript/TypeScript before execution. On Windows,
|
|
861
|
+
return "run_code compatibility rule: its code is parsed as strict JavaScript/TypeScript before execution. Shell commands are nested string data: JavaScript template literals may consume ${...}, backticks, backslashes, and escape sequences before PowerShell, Bash, or POSIX sh sees them. On Windows, avoid embedding PowerShell containing $, ${...}, backslashes, or here-strings in template literals; String.raw does not disable ${...} interpolation. On Linux, prefer ordinary quoted strings or write a script file before invoking bash/sh, especially for commands containing backticks or ${...}. Prefer arrays of ordinary quoted strings joined with \"\\n\", escaping backslashes, or use a file-write tool for large scripts.";
|
|
722
862
|
}
|
|
723
863
|
function localRawImageInstruction(stats) {
|
|
724
864
|
if (stats.failed === 0) return void 0;
|
|
@@ -728,18 +868,25 @@ function supportsImageInput(options) {
|
|
|
728
868
|
return options.provider === "codex-chatgpt" && options.model.toLowerCase().startsWith("gpt-");
|
|
729
869
|
}
|
|
730
870
|
function toolDescriptionForCodex(name, description) {
|
|
731
|
-
if (name === "run_code") return `${description}\n\nCompatibility: code is strict JavaScript/TypeScript
|
|
871
|
+
if (name === "run_code") return `${description}\n\nCompatibility: code is strict JavaScript/TypeScript and nested shell commands are string data. Template literals may consume \${...}, backticks, backslashes, and escape sequences before PowerShell, Bash, or POSIX sh sees them. Prefer ordinary quoted string arrays joined with "\\n", or write a script file with a dedicated file tool before invoking the shell.`;
|
|
732
872
|
if (isCommandTool(name)) return `${description}\n\n${commandToolCompatibilityText(name)}`;
|
|
733
873
|
return description;
|
|
734
874
|
}
|
|
735
875
|
function commandToolInstruction(tools) {
|
|
736
876
|
const names = tools?.filter((tool) => isCommandTool(tool.name)).map((tool) => tool.name);
|
|
737
877
|
if (!names?.length) return void 0;
|
|
738
|
-
|
|
878
|
+
const uniqueNames = [...new Set(names)];
|
|
879
|
+
const normalized = uniqueNames.map((name) => name.toLowerCase());
|
|
880
|
+
const shellGuidance = [
|
|
881
|
+
normalized.some((name) => name === "pwsh" || name.includes("powershell")) ? "For pwsh/PowerShell, use native PowerShell syntax and native Windows paths." : void 0,
|
|
882
|
+
normalized.includes("bash") ? "For bash, use native POSIX paths and Bash syntax in a fresh non-interactive process." : void 0,
|
|
883
|
+
normalized.some((name) => name === "sh" || name === "shell") ? "For sh/generic shell, prefer portable POSIX syntax and avoid Bash-only arrays, [[ ... ]], process substitution, and source." : void 0
|
|
884
|
+
].filter((value) => value !== void 0).join(" ");
|
|
885
|
+
return `Command tool compatibility rule (${uniqueNames.join(", ")}): each command call runs in a fresh process, so do not rely on cd, aliases, functions, or variables from previous calls; set workdir when the tool supports it. ${shellGuidance} For deletion or move operations, first resolve and verify exact absolute target paths, then operate on those literal paths only; avoid dynamically deleting paths built from home-directory expansion, wildcards, command substitution, or another shell's output. Treat [auto-mode hard deny] and similar policy denials as non-retriable; choose a safer non-destructive inspection or report the limitation instead of repeating the same command or adding sandbox escalation. If downloads fail with TLS credential or connection-closed errors, treat that as an environment/network failure and use local sources or report the limitation instead of cycling through equivalent download commands.`;
|
|
739
886
|
}
|
|
740
887
|
function commandToolCompatibilityText(name) {
|
|
741
888
|
const shell = name.toLowerCase();
|
|
742
|
-
return `Compatibility: command execution is stateless between calls.${shell === "pwsh" || shell.includes("powershell") ? " Use native PowerShell syntax and native Windows paths
|
|
889
|
+
return `Compatibility: command execution is stateless between calls.${shell === "pwsh" || shell.includes("powershell") ? " Use native PowerShell syntax and native Windows paths." : shell === "bash" ? " Use Bash syntax and native POSIX paths." : " Use portable POSIX syntax and native POSIX paths; avoid Bash-only arrays, [[ ... ]], process substitution, and source."} Prefer workdir over cd because every call starts a fresh process. For destructive operations, verify exact absolute targets first and use literal paths; policy hard-deny results require a safer command shape, not sandbox escalation.`;
|
|
743
890
|
}
|
|
744
891
|
function sandboxToolInstruction(tools, sandboxRetryTools) {
|
|
745
892
|
if (!tools?.some((tool) => hasSandboxControls(tool.parameters))) return void 0;
|
|
@@ -761,7 +908,7 @@ function toolParametersForCodex(toolName, parameters, allowSandboxRetry) {
|
|
|
761
908
|
const code = record$2(properties.code);
|
|
762
909
|
if (code !== null) {
|
|
763
910
|
const current = typeof code.description === "string" ? code.description.trim() : "";
|
|
764
|
-
const compatibility = "Strict JavaScript/TypeScript source.
|
|
911
|
+
const compatibility = "Strict JavaScript/TypeScript source. Nested shell commands are string data: template literals may consume ${...}, backticks, backslashes, and escape sequences before PowerShell, Bash, or POSIX sh sees them; String.raw still performs ${...} interpolation. Prefer ordinary quoted string arrays joined with \"\\n\", or write a script file with a dedicated file tool.";
|
|
765
912
|
code.description = current ? `${current}\n\n${compatibility}` : compatibility;
|
|
766
913
|
}
|
|
767
914
|
}
|
|
@@ -784,7 +931,7 @@ function appendPropertyDescription(value, addition) {
|
|
|
784
931
|
}
|
|
785
932
|
function isCommandTool(name) {
|
|
786
933
|
const normalized = name.toLowerCase();
|
|
787
|
-
return normalized === "pwsh" || normalized === "powershell" || normalized === "bash" || normalized === "shell";
|
|
934
|
+
return normalized === "pwsh" || normalized === "powershell" || normalized === "bash" || normalized === "sh" || normalized === "shell";
|
|
788
935
|
}
|
|
789
936
|
function hasSandboxControls(parameters) {
|
|
790
937
|
const properties = record$2(parameters.properties);
|
|
@@ -828,7 +975,7 @@ function appendMissingToolCalls(input, knownToolCalls, message) {
|
|
|
828
975
|
}
|
|
829
976
|
function runCodeErrorOutput(output) {
|
|
830
977
|
if (!isRunCodeParserError(output)) return output;
|
|
831
|
-
return `${output}\n\nCompatibility hint: run_code failed while parsing strict JavaScript/TypeScript, before the nested tool ran.
|
|
978
|
+
return `${output}\n\nCompatibility hint: run_code failed while parsing strict JavaScript/TypeScript, before the nested tool ran. Shell commands are nested string data; template literals can consume \${...}, backticks, backslashes, and escape sequences before PowerShell, Bash, or POSIX sh sees them, and String.raw does not prevent \${...} interpolation. Build the script from ordinary quoted strings joined with "\\n", or write a script file with a dedicated file tool and then invoke the shell.`;
|
|
832
979
|
}
|
|
833
980
|
function isRunCodeParserError(output) {
|
|
834
981
|
return /(?:Legacy octal escape is not permitted in strict mode|Unexpected token|Invalid or unexpected token|Unterminated template|Expected ['"]?\}['"]?)/i.test(output);
|
|
@@ -1833,6 +1980,100 @@ function parseStoredCredentials(value) {
|
|
|
1833
1980
|
};
|
|
1834
1981
|
}
|
|
1835
1982
|
//#endregion
|
|
1983
|
+
//#region src/host/token-store-linux.ts
|
|
1984
|
+
const DIRECTORY_MODE = 448;
|
|
1985
|
+
const FILE_MODE = 384;
|
|
1986
|
+
function defaultLinuxCredentialPath() {
|
|
1987
|
+
return join(process.env.DSH_HOME?.trim() || join(homedir(), ".dsh"), "storages", "dsh-chatgpt-subscription", "oauth.json");
|
|
1988
|
+
}
|
|
1989
|
+
/**
|
|
1990
|
+
* Linux credential storage protected by owner-only filesystem permissions.
|
|
1991
|
+
* The payload is not encrypted at rest, so callers must report that distinction
|
|
1992
|
+
* instead of presenting this store as equivalent to Windows DPAPI.
|
|
1993
|
+
*/
|
|
1994
|
+
var LinuxFileTokenStore = class {
|
|
1995
|
+
path;
|
|
1996
|
+
storage = {
|
|
1997
|
+
kind: "linux-file",
|
|
1998
|
+
encrypted: false
|
|
1999
|
+
};
|
|
2000
|
+
noFollow = constants.O_NOFOLLOW;
|
|
2001
|
+
constructor(path = defaultLinuxCredentialPath()) {
|
|
2002
|
+
this.path = path;
|
|
2003
|
+
if (process.platform !== "linux") throw new Error("Linux credential storage requires Linux");
|
|
2004
|
+
if (this.noFollow === void 0) throw new Error("Linux credential storage requires O_NOFOLLOW support");
|
|
2005
|
+
if (dirname(path) === path) throw new Error("invalid Linux credential path");
|
|
2006
|
+
}
|
|
2007
|
+
async load() {
|
|
2008
|
+
let handle;
|
|
2009
|
+
try {
|
|
2010
|
+
handle = await open(this.path, constants.O_RDONLY | this.noFollow);
|
|
2011
|
+
} catch (error) {
|
|
2012
|
+
if (isMissing(error)) return null;
|
|
2013
|
+
throw new Error("Linux credential read failed", { cause: error });
|
|
2014
|
+
}
|
|
2015
|
+
try {
|
|
2016
|
+
const stats = await handle.stat();
|
|
2017
|
+
if (!stats.isFile()) throw new Error("credential path is not a regular file");
|
|
2018
|
+
if (typeof process.getuid === "function" && stats.uid !== process.getuid()) throw new Error("credential file is owned by another user");
|
|
2019
|
+
if ((stats.mode & 511) !== FILE_MODE) throw new Error("credential file permissions must be 0600");
|
|
2020
|
+
const payload = await handle.readFile({ encoding: "utf8" });
|
|
2021
|
+
return parseStoredCredentials(JSON.parse(payload));
|
|
2022
|
+
} catch (error) {
|
|
2023
|
+
throw new Error("Linux credential payload is invalid or insecure", { cause: error });
|
|
2024
|
+
} finally {
|
|
2025
|
+
await handle.close();
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
async save(value) {
|
|
2029
|
+
const directory = dirname(this.path);
|
|
2030
|
+
const temporary = `${this.path}.tmp-${randomUUID()}`;
|
|
2031
|
+
try {
|
|
2032
|
+
const existing = await lstat(this.path);
|
|
2033
|
+
if (existing.isSymbolicLink() || !existing.isFile()) throw new Error("credential path is not a regular file");
|
|
2034
|
+
assertOwnedByCurrentUser(existing.uid, "credential file");
|
|
2035
|
+
} catch (error) {
|
|
2036
|
+
if (!isMissing(error)) throw new Error("Linux credential write failed", { cause: error });
|
|
2037
|
+
}
|
|
2038
|
+
await mkdir(directory, {
|
|
2039
|
+
recursive: true,
|
|
2040
|
+
mode: DIRECTORY_MODE
|
|
2041
|
+
});
|
|
2042
|
+
const directoryStats = await stat(directory);
|
|
2043
|
+
if (!directoryStats.isDirectory()) throw new Error("Linux credential directory is invalid");
|
|
2044
|
+
assertOwnedByCurrentUser(directoryStats.uid, "credential directory");
|
|
2045
|
+
await chmod(directory, DIRECTORY_MODE);
|
|
2046
|
+
let handle;
|
|
2047
|
+
try {
|
|
2048
|
+
handle = await open(temporary, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, FILE_MODE);
|
|
2049
|
+
await handle.writeFile(JSON.stringify(value), { encoding: "utf8" });
|
|
2050
|
+
await handle.sync();
|
|
2051
|
+
await handle.close();
|
|
2052
|
+
handle = void 0;
|
|
2053
|
+
await rename(temporary, this.path);
|
|
2054
|
+
await chmod(this.path, FILE_MODE);
|
|
2055
|
+
} catch (error) {
|
|
2056
|
+
await handle?.close().catch(() => void 0);
|
|
2057
|
+
await unlink(temporary).catch(() => void 0);
|
|
2058
|
+
throw new Error("Linux credential write failed", { cause: error });
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
async clear() {
|
|
2062
|
+
try {
|
|
2063
|
+
await unlink(this.path);
|
|
2064
|
+
} catch (error) {
|
|
2065
|
+
if (isMissing(error)) return;
|
|
2066
|
+
throw new Error("Linux credential deletion failed", { cause: error });
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
};
|
|
2070
|
+
function assertOwnedByCurrentUser(owner, label) {
|
|
2071
|
+
if (typeof process.getuid === "function" && owner !== process.getuid()) throw new Error(`${label} is owned by another user`);
|
|
2072
|
+
}
|
|
2073
|
+
function isMissing(error) {
|
|
2074
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
2075
|
+
}
|
|
2076
|
+
//#endregion
|
|
1836
2077
|
//#region src/host/token-store-windows.ts
|
|
1837
2078
|
const PROTECT_SCRIPT = String.raw`
|
|
1838
2079
|
$ErrorActionPreference = 'Stop'
|
|
@@ -1866,6 +2107,10 @@ function defaultDpapiCredentialPath() {
|
|
|
1866
2107
|
}
|
|
1867
2108
|
var WindowsDpapiTokenStore = class {
|
|
1868
2109
|
path;
|
|
2110
|
+
storage = {
|
|
2111
|
+
kind: "windows-dpapi",
|
|
2112
|
+
encrypted: true
|
|
2113
|
+
};
|
|
1869
2114
|
constructor(path = defaultDpapiCredentialPath()) {
|
|
1870
2115
|
this.path = path;
|
|
1871
2116
|
if (process.platform !== "win32") throw new Error("Windows DPAPI storage requires Windows");
|
|
@@ -1938,14 +2183,22 @@ function runPowerShell(script, path, stdin) {
|
|
|
1938
2183
|
});
|
|
1939
2184
|
}
|
|
1940
2185
|
//#endregion
|
|
2186
|
+
//#region src/host/platform-token-store.ts
|
|
2187
|
+
function createPlatformTokenStore(platform = process.platform) {
|
|
2188
|
+
if (platform === "win32") return new WindowsDpapiTokenStore();
|
|
2189
|
+
if (platform === "linux") return new LinuxFileTokenStore();
|
|
2190
|
+
throw new Error(`Unsupported platform ${platform}; dsh-chatgpt-subscription supports Windows and Linux.`);
|
|
2191
|
+
}
|
|
2192
|
+
//#endregion
|
|
1941
2193
|
//#region src/index.ts
|
|
1942
2194
|
const inject = [
|
|
1943
2195
|
"webServer",
|
|
1944
2196
|
"llm",
|
|
1945
|
-
"attachments"
|
|
2197
|
+
"attachments",
|
|
2198
|
+
"agents"
|
|
1946
2199
|
];
|
|
1947
2200
|
function apply(ctx) {
|
|
1948
|
-
const oauth = new OAuthService(
|
|
2201
|
+
const oauth = new OAuthService(createPlatformTokenStore(), { logger: ctx.logger });
|
|
1949
2202
|
const usage = new UsageService(oauth);
|
|
1950
2203
|
const adapter = new CodexChatGptAdapter(new ResponsesClient(oauth, ctx.attachments, {
|
|
1951
2204
|
localRawImages: { baseUrl: localWebServerBaseUrl(ctx.webServer.host, ctx.webServer.port) },
|
|
@@ -1954,7 +2207,9 @@ function apply(ctx) {
|
|
|
1954
2207
|
ctx.effect(() => {
|
|
1955
2208
|
const disposeRoutes = registerRoutes(ctx, oauth, usage);
|
|
1956
2209
|
const disposeAdapter = ctx.llm.registerAdapter([PROVIDER_ID], adapter);
|
|
2210
|
+
const disposeSubagentReportCompat = installSubagentReportDedupCompat(ctx);
|
|
1957
2211
|
return () => {
|
|
2212
|
+
disposeSubagentReportCompat();
|
|
1958
2213
|
disposeAdapter();
|
|
1959
2214
|
disposeRoutes();
|
|
1960
2215
|
oauth.dispose();
|
|
@@ -1965,4 +2220,4 @@ function localWebServerBaseUrl(host, port) {
|
|
|
1965
2220
|
return `http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}`;
|
|
1966
2221
|
}
|
|
1967
2222
|
//#endregion
|
|
1968
|
-
export { CodexChatGptAdapter, OAuthService, ResponsesClient, UsageService, apply, inject, mapCodexUsage, parseResponsesStream };
|
|
2223
|
+
export { CodexChatGptAdapter, LinuxFileTokenStore, OAuthService, ResponsesClient, UsageService, WindowsDpapiTokenStore, apply, createPlatformTokenStore, inject, mapCodexUsage, parseResponsesStream };
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
|
-
import type { QuotaWindowDto } from '../shared/contracts.ts';
|
|
2
|
+
import type { CredentialStorageDto, QuotaWindowDto } from '../shared/contracts.ts';
|
|
3
3
|
import { NS } from './locales.ts';
|
|
4
4
|
type Props = PropsRuntime<'settings.section'> & PropsLocale<typeof NS>;
|
|
5
5
|
type Translate = Props['t'];
|
|
6
6
|
export declare function CodexSubscriptionSection({ t }: Props): React.JSX.Element;
|
|
7
|
+
export declare function storageLabel(storage: CredentialStorageDto | undefined, t: Translate): string;
|
|
8
|
+
export declare function storageNotice(storage: CredentialStorageDto | undefined, t: Translate): string;
|
|
7
9
|
export declare function QuotaBar({ label, window, t }: {
|
|
8
10
|
label: string;
|
|
9
11
|
window: QuotaWindowDto;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodexSubscriptionSection.d.ts","sourceRoot":"","sources":["../../../src/client/CodexSubscriptionSection.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACjF,OAAO,KAAK,EAAmC,cAAc,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"CodexSubscriptionSection.d.ts","sourceRoot":"","sources":["../../../src/client/CodexSubscriptionSection.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACjF,OAAO,KAAK,EAAE,oBAAoB,EAAmC,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEnH,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAA;AAEjC,KAAK,KAAK,GAAG,YAAY,CAAC,kBAAkB,CAAC,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAA;AAEtE,KAAK,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;AAI3B,wBAAgB,wBAAwB,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAoMxE;AAiBD,wBAAgB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,CAM5F;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,CAM7F;AAUD,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAczH;AAMD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,CAQxE;AAWD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAUnD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAK3E,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAK3E,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AAG/D,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,0BAA0B,EAAE,SAAS,CAAA;KACtC;CACF;AAED,eAAO,MAAM,MAAM,UAAsB,CAAA;AAEzC,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAU9C"}
|
|
@@ -9,8 +9,14 @@ export declare const zh: {
|
|
|
9
9
|
readonly accountId: "账号 ID";
|
|
10
10
|
readonly expires: "令牌到期";
|
|
11
11
|
readonly storage: "凭据存储";
|
|
12
|
-
readonly
|
|
13
|
-
readonly
|
|
12
|
+
readonly storageWindows: "Windows DPAPI(当前用户加密)";
|
|
13
|
+
readonly storageLinuxFile: "Linux 用户私有文件(权限 0600)";
|
|
14
|
+
readonly storageMemory: "仅 Host 内存(不持久化)";
|
|
15
|
+
readonly storageUnavailable: "凭据存储不可用";
|
|
16
|
+
readonly securityWindows: "令牌 Windows CurrentUser DPAPI 加密。";
|
|
17
|
+
readonly securityLinuxFile: "令牌仅写入 Host 上当前 Linux 用户可读的 0600 文件。";
|
|
18
|
+
readonly securityMemory: "令牌仅保留在 Host 内存中,Host 退出后丢失。";
|
|
19
|
+
readonly securityUnavailable: "Host 无法安全访问凭据存储;请修复文件所有者或权限后重试。";
|
|
14
20
|
readonly signIn: "使用 ChatGPT 登录";
|
|
15
21
|
readonly signInAgain: "重新登录";
|
|
16
22
|
readonly cancel: "取消登录";
|
|
@@ -60,8 +66,14 @@ export declare const dictionaries: {
|
|
|
60
66
|
readonly accountId: "账号 ID";
|
|
61
67
|
readonly expires: "令牌到期";
|
|
62
68
|
readonly storage: "凭据存储";
|
|
63
|
-
readonly
|
|
64
|
-
readonly
|
|
69
|
+
readonly storageWindows: "Windows DPAPI(当前用户加密)";
|
|
70
|
+
readonly storageLinuxFile: "Linux 用户私有文件(权限 0600)";
|
|
71
|
+
readonly storageMemory: "仅 Host 内存(不持久化)";
|
|
72
|
+
readonly storageUnavailable: "凭据存储不可用";
|
|
73
|
+
readonly securityWindows: "令牌由 Host 使用 Windows CurrentUser DPAPI 加密,不会进入浏览器、settings.yaml 或日志。";
|
|
74
|
+
readonly securityLinuxFile: "令牌仅写入 Host 上当前 Linux 用户可读的 0600 文件,但不会额外加密;同 UID 进程、root、备份和磁盘快照仍可能读取。";
|
|
75
|
+
readonly securityMemory: "令牌仅保留在 Host 内存中,Host 退出后丢失。";
|
|
76
|
+
readonly securityUnavailable: "Host 无法安全访问凭据存储;请修复文件所有者或权限后重试。";
|
|
65
77
|
readonly signIn: "使用 ChatGPT 登录";
|
|
66
78
|
readonly signInAgain: "重新登录";
|
|
67
79
|
readonly cancel: "取消登录";
|
|
@@ -98,6 +110,6 @@ export declare const dictionaries: {
|
|
|
98
110
|
readonly retry: "重试";
|
|
99
111
|
readonly unknown: "未知";
|
|
100
112
|
};
|
|
101
|
-
en: Record<"
|
|
113
|
+
en: Record<"quota" | "account" | "storage" | "stale" | "pending" | "title" | "intro" | "signedOut" | "signedIn" | "plan" | "accountId" | "expires" | "storageWindows" | "storageLinuxFile" | "storageMemory" | "storageUnavailable" | "securityWindows" | "securityLinuxFile" | "securityMemory" | "securityUnavailable" | "signIn" | "signInAgain" | "cancel" | "signOut" | "refreshToken" | "popupBlocked" | "continueLogin" | "loading" | "connection" | "provider" | "connectionState" | "connected" | "untested" | "testConnection" | "testing" | "latency" | "models" | "quotaIntro" | "refreshQuota" | "refreshing" | "noQuota" | "quotaSignedOut" | "updated" | "primary" | "secondary" | "limitWindow" | "used" | "remaining" | "exhausted" | "resets" | "retry" | "unknown", string>;
|
|
102
114
|
};
|
|
103
115
|
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE,EAAG,0BAAmC,CAAA;AAErD,eAAO,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE,EAAG,0BAAmC,CAAA;AAErD,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDL,CAAA;AAEV,eAAO,MAAM,EAAE,EAAE,MAAM,CAAC,MAAM,OAAO,EAAE,EAAE,MAAM,CAqD9C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,EAAE,CAAA;AACvC,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAa,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/client/styles.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/client/styles.ts"],"names":[],"mappings":"AAiDA,wBAAgB,aAAa,IAAI,MAAM,IAAI,CAQ1C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-service.d.ts","sourceRoot":"","sources":["../../../src/host/oauth-service.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,cAAc,EACf,MAAM,wBAAwB,CAAA;AAE/B,OAAO,KAAK,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE1E,KAAK,SAAS,GAAG,OAAO,KAAK,CAAA;AAC7B,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;AASnD,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IACvC,6BAA6B,CAAC,EAAE;QAC9B,kBAAkB,CAAC,EAAE,OAAO,CAAA;QAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAA;QAC3B,aAAa,CAAC,EAAE,KAAK,CAAC;YAAE,EAAE,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC,CAAA;KACxC,CAAA;CACF;AASD,qBAAa,iBAAkB,SAAQ,KAAK;IAC9B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC;gBAA5B,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM;CAInE;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IACjC,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;IACvC,+EAA+E;IAC/E,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,qBAAa,YAAY;IAaX,OAAO,CAAC,QAAQ,CAAC,KAAK;IAZlC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;IAClE,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,cAAc,CAA+C;IACrE,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAQ;gBAEK,KAAK,EAAE,UAAU,EAAE,OAAO,GAAE,mBAAwB;IAQ3E,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC;IAYjC,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth-service.d.ts","sourceRoot":"","sources":["../../../src/host/oauth-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-token-store.d.ts","sourceRoot":"","sources":["../../../src/host/platform-token-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAIlD,wBAAgB,wBAAwB,CAAC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,UAAU,CAIjG"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
/**
|
|
3
|
+
* DSH_COMPAT_REMOVE(subagent-report-settlement-dedup)
|
|
4
|
+
*
|
|
5
|
+
* Temporary compatibility shim for DSH 0.1.0-rc.6. A continuable child is told
|
|
6
|
+
* to report its result before finishing, while DSH also unconditionally sends
|
|
7
|
+
* the same closing output in a `subagent-settled` notice. The report is often
|
|
8
|
+
* still queued when the settlement reaches the parent, so the parent sees the
|
|
9
|
+
* result once and the equivalent report remains as duplicate next-turn work.
|
|
10
|
+
*
|
|
11
|
+
* Remove this module, its installation in `src/index.ts`, and its focused test
|
|
12
|
+
* once upstream coalesces an equivalent final report with settlement delivery.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DSH_SUBAGENT_REPORT_DEDUP_COMPAT_MARKER: "__dshChatgptSubscriptionSubagentReportDedupCompatV1";
|
|
15
|
+
/**
|
|
16
|
+
* Discard only an exact, same-child report duplicate immediately before DSH
|
|
17
|
+
* delivers the corresponding settlement notice. Partial reports, reports with
|
|
18
|
+
* different content, and all unrelated inbox work remain untouched.
|
|
19
|
+
*/
|
|
20
|
+
export declare function installSubagentReportDedupCompat(ctx: Context): () => void;
|
|
21
|
+
//# sourceMappingURL=subagent-report-scheduling-compat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-report-scheduling-compat.d.ts","sourceRoot":"","sources":["../../../src/host/subagent-report-scheduling-compat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uCAAuC,EAClD,qDAA8D,CAAA;AA4EhE;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,IAAI,CAyGzE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TokenStore, StoredOAuthCredentials } from './token-store.ts';
|
|
2
|
+
export declare function defaultLinuxCredentialPath(): string;
|
|
3
|
+
/**
|
|
4
|
+
* Linux credential storage protected by owner-only filesystem permissions.
|
|
5
|
+
* The payload is not encrypted at rest, so callers must report that distinction
|
|
6
|
+
* instead of presenting this store as equivalent to Windows DPAPI.
|
|
7
|
+
*/
|
|
8
|
+
export declare class LinuxFileTokenStore implements TokenStore {
|
|
9
|
+
private readonly path;
|
|
10
|
+
readonly storage: {
|
|
11
|
+
readonly kind: "linux-file";
|
|
12
|
+
readonly encrypted: false;
|
|
13
|
+
};
|
|
14
|
+
private readonly noFollow;
|
|
15
|
+
constructor(path?: string);
|
|
16
|
+
load(): Promise<StoredOAuthCredentials | null>;
|
|
17
|
+
save(value: StoredOAuthCredentials): Promise<void>;
|
|
18
|
+
clear(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=token-store-linux.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-store-linux.d.ts","sourceRoot":"","sources":["../../../src/host/token-store-linux.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAM1E,wBAAgB,0BAA0B,IAAI,MAAM,CAGnD;AAED;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,UAAU;IAIxC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,QAAQ,CAAC,OAAO;;;MAAoD;IACpE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;gBAEnB,IAAI,SAA+B;IAM1D,IAAI,IAAI,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC;IA2B9C,IAAI,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkClD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B"}
|
|
@@ -2,6 +2,10 @@ import type { TokenStore, StoredOAuthCredentials } from './token-store.ts';
|
|
|
2
2
|
export declare function defaultDpapiCredentialPath(): string;
|
|
3
3
|
export declare class WindowsDpapiTokenStore implements TokenStore {
|
|
4
4
|
private readonly path;
|
|
5
|
+
readonly storage: {
|
|
6
|
+
readonly kind: "windows-dpapi";
|
|
7
|
+
readonly encrypted: true;
|
|
8
|
+
};
|
|
5
9
|
constructor(path?: string);
|
|
6
10
|
load(): Promise<StoredOAuthCredentials | null>;
|
|
7
11
|
save(value: StoredOAuthCredentials): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-store-windows.d.ts","sourceRoot":"","sources":["../../../src/host/token-store-windows.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAiC1E,wBAAgB,0BAA0B,IAAI,MAAM,CAGnD;AAED,qBAAa,sBAAuB,YAAW,UAAU;
|
|
1
|
+
{"version":3,"file":"token-store-windows.d.ts","sourceRoot":"","sources":["../../../src/host/token-store-windows.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAiC1E,wBAAgB,0BAA0B,IAAI,MAAM,CAGnD;AAED,qBAAa,sBAAuB,YAAW,UAAU;IAG3C,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,QAAQ,CAAC,OAAO;;;MAAsD;gBAEzC,IAAI,SAA+B;IAK1D,IAAI,IAAI,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC;IAW9C,IAAI,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CredentialStorageDto } from '../shared/contracts.ts';
|
|
1
2
|
export interface StoredOAuthCredentials {
|
|
2
3
|
accessToken: string;
|
|
3
4
|
refreshToken: string;
|
|
@@ -8,12 +9,17 @@ export interface StoredOAuthCredentials {
|
|
|
8
9
|
planType?: string;
|
|
9
10
|
}
|
|
10
11
|
export interface TokenStore {
|
|
12
|
+
readonly storage: Omit<CredentialStorageDto, 'available'>;
|
|
11
13
|
load(): Promise<StoredOAuthCredentials | null>;
|
|
12
14
|
save(value: StoredOAuthCredentials): Promise<void>;
|
|
13
15
|
clear(): Promise<void>;
|
|
14
16
|
}
|
|
15
17
|
/** Test seam and non-persistent development store. Never used by apply(). */
|
|
16
18
|
export declare class MemoryTokenStore implements TokenStore {
|
|
19
|
+
readonly storage: {
|
|
20
|
+
readonly kind: "memory";
|
|
21
|
+
readonly encrypted: false;
|
|
22
|
+
};
|
|
17
23
|
private value;
|
|
18
24
|
load(): Promise<StoredOAuthCredentials | null>;
|
|
19
25
|
save(value: StoredOAuthCredentials): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-store.d.ts","sourceRoot":"","sources":["../../../src/host/token-store.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACrC,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,UAAU;IACzB,IAAI,IAAI,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAA;IAC9C,IAAI,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAED,6EAA6E;AAC7E,qBAAa,gBAAiB,YAAW,UAAU;IACjD,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,CAqB7E"}
|
|
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,sBAAsB;IACrC,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,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAA;IACzD,IAAI,IAAI,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAA;IAC9C,IAAI,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;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,CAqB7E"}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -5,5 +5,8 @@ export { OAuthService } from './host/oauth-service.ts';
|
|
|
5
5
|
export { CodexChatGptAdapter } from './host/adapter.ts';
|
|
6
6
|
export { ResponsesClient, parseResponsesStream } from './host/responses-client.ts';
|
|
7
7
|
export { UsageService, mapCodexUsage } from './host/usage-service.ts';
|
|
8
|
+
export { createPlatformTokenStore } from './host/platform-token-store.ts';
|
|
9
|
+
export { LinuxFileTokenStore } from './host/token-store-linux.ts';
|
|
10
|
+
export { WindowsDpapiTokenStore } from './host/token-store-windows.ts';
|
|
8
11
|
export type { TokenStore, StoredOAuthCredentials } from './host/token-store.ts';
|
|
9
12
|
//# sourceMappingURL=index.d.ts.map
|