@mandujs/core 0.41.0 → 0.41.2
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/package.json
CHANGED
|
@@ -32,6 +32,7 @@ describe("resolveBrainAdapter — priority order", () => {
|
|
|
32
32
|
adapter: "auto",
|
|
33
33
|
credentialStore: store,
|
|
34
34
|
probeOllama: async () => true,
|
|
35
|
+
probeChatGPTAuth: () => ({ authenticated: false, path: null }),
|
|
35
36
|
});
|
|
36
37
|
expect(res.resolved).toBe("openai");
|
|
37
38
|
expect(res.adapter.name).toBe("openai-oauth");
|
|
@@ -43,6 +44,7 @@ describe("resolveBrainAdapter — priority order", () => {
|
|
|
43
44
|
adapter: "auto",
|
|
44
45
|
credentialStore: store,
|
|
45
46
|
probeOllama: async () => true,
|
|
47
|
+
probeChatGPTAuth: () => ({ authenticated: false, path: null }),
|
|
46
48
|
});
|
|
47
49
|
expect(res.resolved).toBe("anthropic");
|
|
48
50
|
expect(res.adapter.name).toBe("anthropic-oauth");
|
|
@@ -54,6 +56,7 @@ describe("resolveBrainAdapter — priority order", () => {
|
|
|
54
56
|
adapter: "auto",
|
|
55
57
|
credentialStore: store,
|
|
56
58
|
probeOllama: async () => true,
|
|
59
|
+
probeChatGPTAuth: () => ({ authenticated: false, path: null }),
|
|
57
60
|
});
|
|
58
61
|
expect(res.resolved).toBe("ollama");
|
|
59
62
|
expect(res.adapter.name).toBe("ollama");
|
|
@@ -65,6 +68,7 @@ describe("resolveBrainAdapter — priority order", () => {
|
|
|
65
68
|
adapter: "auto",
|
|
66
69
|
credentialStore: store,
|
|
67
70
|
probeOllama: async () => false,
|
|
71
|
+
probeChatGPTAuth: () => ({ authenticated: false, path: null }),
|
|
68
72
|
});
|
|
69
73
|
expect(res.resolved).toBe("template");
|
|
70
74
|
expect(res.adapter.name).toBe("noop");
|
|
@@ -104,6 +108,7 @@ describe("resolveBrainAdapter — explicit pins degrade gracefully", () => {
|
|
|
104
108
|
const res = await resolveBrainAdapter({
|
|
105
109
|
adapter: "openai",
|
|
106
110
|
credentialStore: store,
|
|
111
|
+
probeChatGPTAuth: () => ({ authenticated: false, path: null }),
|
|
107
112
|
});
|
|
108
113
|
expect(res.resolved).toBe("template");
|
|
109
114
|
expect(res.reason).toContain("no token");
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
createOpenAIOAuthAdapter,
|
|
35
35
|
type OpenAIOAuthAdapterOptions,
|
|
36
36
|
} from "./openai-oauth";
|
|
37
|
+
import { ChatGPTAuth } from "./chatgpt-auth";
|
|
37
38
|
import {
|
|
38
39
|
AnthropicOAuthAdapter,
|
|
39
40
|
createAnthropicOAuthAdapter,
|
|
@@ -82,6 +83,13 @@ export interface BrainAdapterConfig {
|
|
|
82
83
|
* default consults `credentialStore.load(provider)`.
|
|
83
84
|
*/
|
|
84
85
|
probeToken?: (provider: "openai" | "anthropic") => Promise<StoredToken | null>;
|
|
86
|
+
/**
|
|
87
|
+
* Override the ChatGPT session-token probe. Default: instantiate
|
|
88
|
+
* `new ChatGPTAuth()` and check its on-disk auth.json. Tests inject
|
|
89
|
+
* a stub returning `false` so the developer's real `~/.codex/auth.json`
|
|
90
|
+
* doesn't leak into unit-test expectations.
|
|
91
|
+
*/
|
|
92
|
+
probeChatGPTAuth?: () => { authenticated: boolean; path: string | null };
|
|
85
93
|
}
|
|
86
94
|
|
|
87
95
|
/**
|
|
@@ -122,6 +130,13 @@ export async function resolveBrainAdapter(
|
|
|
122
130
|
config.probeOllama ??
|
|
123
131
|
(async (ollama: OllamaAdapter) => ollama.isServerRunning());
|
|
124
132
|
|
|
133
|
+
const probeChatGPTAuth =
|
|
134
|
+
config.probeChatGPTAuth ??
|
|
135
|
+
(() => {
|
|
136
|
+
const c = new ChatGPTAuth();
|
|
137
|
+
return { authenticated: c.isAuthenticated(), path: c.locateAuthFile() };
|
|
138
|
+
});
|
|
139
|
+
|
|
125
140
|
// Explicit template — skip every other check.
|
|
126
141
|
if (requested === "template") {
|
|
127
142
|
return {
|
|
@@ -145,14 +160,17 @@ export async function resolveBrainAdapter(
|
|
|
145
160
|
"adapter: 'openai' requested but telemetryOptOut=true — forcing template",
|
|
146
161
|
};
|
|
147
162
|
}
|
|
148
|
-
|
|
149
|
-
|
|
163
|
+
// Primary: ChatGPT session token (written by `@openai/codex login`).
|
|
164
|
+
const cg = probeChatGPTAuth();
|
|
165
|
+
const hasChatGPT = cg.authenticated;
|
|
166
|
+
const token = hasChatGPT ? null : await probeToken("openai");
|
|
167
|
+
if (!hasChatGPT && !token) {
|
|
150
168
|
return {
|
|
151
169
|
adapter: new NoopAdapter(),
|
|
152
170
|
resolved: "template",
|
|
153
171
|
requested,
|
|
154
172
|
reason:
|
|
155
|
-
"adapter: 'openai' requested but no token
|
|
173
|
+
"adapter: 'openai' requested but no token found — run `mandu brain login --provider=openai`",
|
|
156
174
|
};
|
|
157
175
|
}
|
|
158
176
|
return {
|
|
@@ -164,7 +182,9 @@ export async function resolveBrainAdapter(
|
|
|
164
182
|
}),
|
|
165
183
|
resolved: "openai",
|
|
166
184
|
requested,
|
|
167
|
-
reason:
|
|
185
|
+
reason: hasChatGPT
|
|
186
|
+
? "Explicit adapter: 'openai' + ChatGPT session token present"
|
|
187
|
+
: "Explicit adapter: 'openai' + keychain token present",
|
|
168
188
|
};
|
|
169
189
|
}
|
|
170
190
|
|
|
@@ -217,6 +237,21 @@ export async function resolveBrainAdapter(
|
|
|
217
237
|
// Auto — try cloud providers first (when allowed), then ollama,
|
|
218
238
|
// then template.
|
|
219
239
|
if (!telemetryOptOut) {
|
|
240
|
+
// Primary: ChatGPT session token (managed by `@openai/codex`).
|
|
241
|
+
const cg2 = probeChatGPTAuth();
|
|
242
|
+
if (cg2.authenticated) {
|
|
243
|
+
return {
|
|
244
|
+
adapter: createOpenAIOAuthAdapter({
|
|
245
|
+
...(config.openaiOptions ?? {}),
|
|
246
|
+
model: config.openai?.model ?? config.openaiOptions?.model,
|
|
247
|
+
credentialStore: store,
|
|
248
|
+
projectRoot,
|
|
249
|
+
}),
|
|
250
|
+
resolved: "openai",
|
|
251
|
+
requested,
|
|
252
|
+
reason: `auto: ChatGPT session token at ${cg2.path ?? "(unknown)"}`,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
220
255
|
const openaiToken = await probeToken("openai");
|
|
221
256
|
if (openaiToken) {
|
|
222
257
|
return {
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version marker — consumers (notably `@mandujs/mcp`) use this to detect
|
|
3
|
+
* that a stale nested copy of `@mandujs/core` was resolved and produce
|
|
4
|
+
* a helpful error instead of a cryptic "X is not a function". See #236.
|
|
5
|
+
*
|
|
6
|
+
* Read directly from the package's own `package.json` at module load
|
|
7
|
+
* time so the value can NEVER drift from the real published version.
|
|
8
|
+
* Best-effort — falls back to "unknown" if the file cannot be read
|
|
9
|
+
* (e.g. when the bundler strips `package.json` from the tree; we never
|
|
10
|
+
* strip it but keep this defensive).
|
|
11
|
+
*/
|
|
12
|
+
export const __MANDU_CORE_VERSION__: string = (() => {
|
|
13
|
+
try {
|
|
14
|
+
// `import.meta.dir` → `<install>/src`; package.json is one level up.
|
|
15
|
+
const pkgPath = `${import.meta.dir}/../package.json`;
|
|
16
|
+
const raw = require("node:fs").readFileSync(pkgPath, "utf-8") as string;
|
|
17
|
+
const parsed = JSON.parse(raw) as { version?: string };
|
|
18
|
+
return typeof parsed.version === "string" ? parsed.version : "unknown";
|
|
19
|
+
} catch {
|
|
20
|
+
return "unknown";
|
|
21
|
+
}
|
|
22
|
+
})();
|
|
23
|
+
|
|
1
24
|
export * from "./spec";
|
|
2
25
|
export * from "./runtime";
|
|
3
26
|
export * from "./generator";
|