patchwork-os 0.2.0-alpha.2 → 0.2.0-alpha.4
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/dist/bridge.js +23 -10
- package/dist/bridge.js.map +1 -1
- package/dist/claudeDriver.d.ts +3 -1
- package/dist/claudeDriver.js +48 -0
- package/dist/claudeDriver.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +5 -2
- package/dist/config.js.map +1 -1
- package/dist/connectors/github.d.ts +58 -8
- package/dist/connectors/github.js +321 -84
- package/dist/connectors/github.js.map +1 -1
- package/dist/connectors/gmail.js +21 -0
- package/dist/connectors/gmail.js.map +1 -1
- package/dist/connectors/googleCalendar.d.ts +57 -0
- package/dist/connectors/googleCalendar.js +308 -0
- package/dist/connectors/googleCalendar.js.map +1 -0
- package/dist/connectors/linear.d.ts +100 -0
- package/dist/connectors/linear.js +236 -0
- package/dist/connectors/linear.js.map +1 -0
- package/dist/connectors/mcpClient.d.ts +56 -0
- package/dist/connectors/mcpClient.js +189 -0
- package/dist/connectors/mcpClient.js.map +1 -0
- package/dist/connectors/mcpOAuth.d.ts +73 -0
- package/dist/connectors/mcpOAuth.js +338 -0
- package/dist/connectors/mcpOAuth.js.map +1 -0
- package/dist/connectors/sentry.d.ts +43 -0
- package/dist/connectors/sentry.js +197 -0
- package/dist/connectors/sentry.js.map +1 -0
- package/dist/drivers/claude/api.d.ts +11 -0
- package/dist/drivers/claude/api.js +54 -0
- package/dist/drivers/claude/api.js.map +1 -0
- package/dist/drivers/claude/envSanitizer.d.ts +7 -0
- package/dist/drivers/claude/envSanitizer.js +18 -0
- package/dist/drivers/claude/envSanitizer.js.map +1 -0
- package/dist/drivers/claude/streamParser.d.ts +38 -0
- package/dist/drivers/claude/streamParser.js +34 -0
- package/dist/drivers/claude/streamParser.js.map +1 -0
- package/dist/drivers/claude/subprocess.d.ts +19 -0
- package/dist/drivers/claude/subprocess.js +216 -0
- package/dist/drivers/claude/subprocess.js.map +1 -0
- package/dist/drivers/claude/subprocessSettings.d.ts +9 -0
- package/dist/drivers/claude/subprocessSettings.js +55 -0
- package/dist/drivers/claude/subprocessSettings.js.map +1 -0
- package/dist/drivers/gemini/index.d.ts +14 -0
- package/dist/drivers/gemini/index.js +176 -0
- package/dist/drivers/gemini/index.js.map +1 -0
- package/dist/drivers/grok/index.d.ts +11 -0
- package/dist/drivers/grok/index.js +22 -0
- package/dist/drivers/grok/index.js.map +1 -0
- package/dist/drivers/index.d.ts +18 -0
- package/dist/drivers/index.js +31 -0
- package/dist/drivers/index.js.map +1 -0
- package/dist/drivers/openai/index.d.ts +24 -0
- package/dist/drivers/openai/index.js +110 -0
- package/dist/drivers/openai/index.js.map +1 -0
- package/dist/drivers/types.d.ts +72 -0
- package/dist/drivers/types.js +30 -0
- package/dist/drivers/types.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/recipes/yamlRunner.js +57 -2
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/recipesHttp.d.ts +13 -1
- package/dist/recipesHttp.js +9 -1
- package/dist/recipesHttp.js.map +1 -1
- package/dist/server.d.ts +3 -1
- package/dist/server.js +277 -14
- package/dist/server.js.map +1 -1
- package/dist/tools/createLinearIssue.d.ts +84 -0
- package/dist/tools/createLinearIssue.js +146 -0
- package/dist/tools/createLinearIssue.js.map +1 -0
- package/dist/tools/ctxGetTaskContext.d.ts +4 -1
- package/dist/tools/ctxGetTaskContext.js +45 -2
- package/dist/tools/ctxGetTaskContext.js.map +1 -1
- package/dist/tools/fetchCalendarEvents.d.ts +94 -0
- package/dist/tools/fetchCalendarEvents.js +97 -0
- package/dist/tools/fetchCalendarEvents.js.map +1 -0
- package/dist/tools/fetchGithubIssue.d.ts +80 -0
- package/dist/tools/fetchGithubIssue.js +84 -0
- package/dist/tools/fetchGithubIssue.js.map +1 -0
- package/dist/tools/fetchGithubPR.d.ts +89 -0
- package/dist/tools/fetchGithubPR.js +96 -0
- package/dist/tools/fetchGithubPR.js.map +1 -0
- package/dist/tools/fetchLinearIssue.d.ts +112 -0
- package/dist/tools/fetchLinearIssue.js +129 -0
- package/dist/tools/fetchLinearIssue.js.map +1 -0
- package/dist/tools/fetchSentryIssue.d.ts +143 -0
- package/dist/tools/fetchSentryIssue.js +150 -0
- package/dist/tools/fetchSentryIssue.js.map +1 -0
- package/dist/tools/index.js +12 -0
- package/dist/tools/index.js.map +1 -1
- package/package.json +2 -2
- package/scripts/start-all.sh +56 -19
- package/templates/recipes/ctx-loop-test.yaml +75 -0
- package/templates/recipes/morning-brief.yaml +20 -3
- package/templates/recipes/sentry-to-linear.yaml +77 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { sanitizeEnv } from "../claude/envSanitizer.js";
|
|
3
|
+
import { splitLines } from "../claude/streamParser.js";
|
|
4
|
+
import { toProviderTaskOutcome } from "../types.js";
|
|
5
|
+
const OUTPUT_CAP = 50 * 1024;
|
|
6
|
+
function scrubSecrets(text) {
|
|
7
|
+
return text
|
|
8
|
+
.replace(/AIza[A-Za-z0-9_-]{35}/g, "[REDACTED_API_KEY]")
|
|
9
|
+
.replace(/Bearer\s+[A-Za-z0-9._-]{16,}/gi, "Bearer [REDACTED]");
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* GeminiSubprocessDriver — spawns `gemini -p` with --output-format stream-json.
|
|
13
|
+
* Auth: GEMINI_API_KEY env var (or gcloud ADC / Vertex if configured in ~/.gemini/settings.json).
|
|
14
|
+
* providerOptions: { approvalMode?: "yolo" | "auto_edit" | "default" | "plan" }
|
|
15
|
+
*/
|
|
16
|
+
export class GeminiSubprocessDriver {
|
|
17
|
+
binary;
|
|
18
|
+
log;
|
|
19
|
+
name = "gemini";
|
|
20
|
+
constructor(binary, log) {
|
|
21
|
+
this.binary = binary;
|
|
22
|
+
this.log = log;
|
|
23
|
+
}
|
|
24
|
+
async run(input) {
|
|
25
|
+
const opts = input.providerOptions ?? {};
|
|
26
|
+
const approvalMode = typeof opts.approvalMode === "string" ? opts.approvalMode : "yolo";
|
|
27
|
+
const args = [
|
|
28
|
+
"-p",
|
|
29
|
+
input.prompt,
|
|
30
|
+
"--output-format",
|
|
31
|
+
"stream-json",
|
|
32
|
+
"--approval-mode",
|
|
33
|
+
approvalMode,
|
|
34
|
+
];
|
|
35
|
+
if (input.model)
|
|
36
|
+
args.push("-m", input.model);
|
|
37
|
+
// contextFiles: pass as --include-directories for directory paths
|
|
38
|
+
for (const f of input.contextFiles ?? []) {
|
|
39
|
+
if (typeof f === "string" && f.length > 0 && !f.startsWith("-")) {
|
|
40
|
+
args.push("--include-directories", f);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Strip MCP_* and CLAUDECODE vars; preserve GEMINI_API_KEY + GOOGLE_* vars
|
|
44
|
+
const env = sanitizeEnv(process.env);
|
|
45
|
+
// Also strip Claude-specific auth vars that could confuse Gemini
|
|
46
|
+
for (const key of Object.keys(env)) {
|
|
47
|
+
if (key.startsWith("ANTHROPIC_") || key === "CLAUDE_API_KEY") {
|
|
48
|
+
delete env[key];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
this.log(`[GeminiSubprocessDriver] spawning: ${this.binary} -p <prompt> (workspace: ${input.workspace})`);
|
|
52
|
+
const child = spawn(this.binary, args, {
|
|
53
|
+
cwd: input.workspace,
|
|
54
|
+
env,
|
|
55
|
+
signal: input.signal,
|
|
56
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
57
|
+
detached: true,
|
|
58
|
+
});
|
|
59
|
+
let lineBuf = "";
|
|
60
|
+
let accumulated = "";
|
|
61
|
+
let outputBytesSent = 0;
|
|
62
|
+
let firstAssistantAt;
|
|
63
|
+
let doneFromResult = false;
|
|
64
|
+
let resultSuccess = true;
|
|
65
|
+
child.stdout.setEncoding("utf-8");
|
|
66
|
+
child.stdout.on("data", (chunk) => {
|
|
67
|
+
const { lines, remainder } = splitLines(lineBuf, chunk);
|
|
68
|
+
lineBuf = remainder;
|
|
69
|
+
for (const line of lines) {
|
|
70
|
+
if (line.trim() === "")
|
|
71
|
+
continue;
|
|
72
|
+
let event;
|
|
73
|
+
try {
|
|
74
|
+
event = JSON.parse(line);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Non-JSON stderr/warning lines — skip (Gemini prints "YOLO mode..." to stdout)
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (event.type === "message" &&
|
|
81
|
+
event.role === "assistant" &&
|
|
82
|
+
event.content) {
|
|
83
|
+
if (firstAssistantAt === undefined)
|
|
84
|
+
firstAssistantAt = Date.now();
|
|
85
|
+
const text = event.content;
|
|
86
|
+
accumulated += text;
|
|
87
|
+
if (outputBytesSent < OUTPUT_CAP) {
|
|
88
|
+
const send = text.slice(0, OUTPUT_CAP - outputBytesSent);
|
|
89
|
+
if (send.length > 0) {
|
|
90
|
+
input.onChunk?.(send);
|
|
91
|
+
outputBytesSent += send.length;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (event.type === "result") {
|
|
96
|
+
doneFromResult = true;
|
|
97
|
+
resultSuccess = event.status === "success";
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
let stderr = "";
|
|
102
|
+
child.stderr.setEncoding("utf-8");
|
|
103
|
+
child.stderr.on("data", (chunk) => {
|
|
104
|
+
if (stderr.length < OUTPUT_CAP) {
|
|
105
|
+
stderr += chunk;
|
|
106
|
+
if (stderr.length > OUTPUT_CAP)
|
|
107
|
+
stderr = stderr.slice(0, OUTPUT_CAP);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
const start = Date.now();
|
|
111
|
+
const stderrTailOf = (s) => s.length > 0 ? scrubSecrets(s.slice(-2048)) : undefined;
|
|
112
|
+
const startupMsOf = () => firstAssistantAt !== undefined ? firstAssistantAt - start : undefined;
|
|
113
|
+
let startupTimedOut = false;
|
|
114
|
+
const startupHandle = input.startupTimeoutMs
|
|
115
|
+
? setTimeout(() => {
|
|
116
|
+
if (firstAssistantAt === undefined && !doneFromResult) {
|
|
117
|
+
startupTimedOut = true;
|
|
118
|
+
child.kill();
|
|
119
|
+
}
|
|
120
|
+
}, input.startupTimeoutMs)
|
|
121
|
+
: null;
|
|
122
|
+
let exitCode;
|
|
123
|
+
try {
|
|
124
|
+
exitCode = await new Promise((resolve, reject) => {
|
|
125
|
+
child.on("close", (code) => resolve(code ?? 0));
|
|
126
|
+
child.on("error", reject);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
if (startupHandle)
|
|
131
|
+
clearTimeout(startupHandle);
|
|
132
|
+
const isAbort = (err instanceof Error && err.name === "AbortError") ||
|
|
133
|
+
input.signal.aborted;
|
|
134
|
+
if (isAbort) {
|
|
135
|
+
return {
|
|
136
|
+
text: accumulated.slice(0, OUTPUT_CAP),
|
|
137
|
+
durationMs: Date.now() - start,
|
|
138
|
+
wasAborted: true,
|
|
139
|
+
startupMs: startupMsOf(),
|
|
140
|
+
stderrTail: stderrTailOf(stderr),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
throw err;
|
|
144
|
+
}
|
|
145
|
+
if (startupHandle)
|
|
146
|
+
clearTimeout(startupHandle);
|
|
147
|
+
if (startupTimedOut) {
|
|
148
|
+
return {
|
|
149
|
+
text: accumulated.slice(0, OUTPUT_CAP),
|
|
150
|
+
durationMs: Date.now() - start,
|
|
151
|
+
wasAborted: true,
|
|
152
|
+
startupTimedOut: true,
|
|
153
|
+
stderrTail: stderrTailOf(stderr),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const effectiveExitCode = doneFromResult
|
|
157
|
+
? resultSuccess
|
|
158
|
+
? 0
|
|
159
|
+
: 1
|
|
160
|
+
: exitCode;
|
|
161
|
+
if (effectiveExitCode !== 0 && stderr) {
|
|
162
|
+
this.log(`[GeminiSubprocessDriver] stderr: ${stderr.slice(0, 500)}`);
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
text: accumulated.slice(0, OUTPUT_CAP),
|
|
166
|
+
exitCode: effectiveExitCode,
|
|
167
|
+
durationMs: Date.now() - start,
|
|
168
|
+
stderrTail: stderrTailOf(stderr),
|
|
169
|
+
startupMs: startupMsOf(),
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
async runOutcome(input) {
|
|
173
|
+
return toProviderTaskOutcome(await this.run(input));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/drivers/gemini/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { OpenAIApiDriver } from "../openai/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Grok driver — xAI's API is OpenAI-compatible at https://api.x.ai/v1.
|
|
4
|
+
* Requires XAI_API_KEY environment variable.
|
|
5
|
+
* Install: npm install openai (reuses OpenAI SDK with custom baseURL)
|
|
6
|
+
*/
|
|
7
|
+
export declare class GrokApiDriver extends OpenAIApiDriver {
|
|
8
|
+
readonly name = "grok";
|
|
9
|
+
constructor(log: (msg: string) => void);
|
|
10
|
+
protected apiKey(): string | undefined;
|
|
11
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { OpenAIApiDriver } from "../openai/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Grok driver — xAI's API is OpenAI-compatible at https://api.x.ai/v1.
|
|
4
|
+
* Requires XAI_API_KEY environment variable.
|
|
5
|
+
* Install: npm install openai (reuses OpenAI SDK with custom baseURL)
|
|
6
|
+
*/
|
|
7
|
+
export class GrokApiDriver extends OpenAIApiDriver {
|
|
8
|
+
name = "grok";
|
|
9
|
+
constructor(log) {
|
|
10
|
+
if (!process.env.XAI_API_KEY) {
|
|
11
|
+
throw new Error("GrokApiDriver requires XAI_API_KEY environment variable");
|
|
12
|
+
}
|
|
13
|
+
super(log, {
|
|
14
|
+
baseURL: "https://api.x.ai/v1",
|
|
15
|
+
defaultModel: "grok-2-latest",
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
apiKey() {
|
|
19
|
+
return process.env.XAI_API_KEY;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/drivers/grok/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;GAIG;AACH,MAAM,OAAO,aAAc,SAAQ,eAAe;IAC9B,IAAI,GAAG,MAAM,CAAC;IAEhC,YAAY,GAA0B;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CACb,yDAAyD,CAC1D,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,GAAG,EAAE;YACT,OAAO,EAAE,qBAAqB;YAC9B,YAAY,EAAE,eAAe;SAC9B,CAAC,CAAC;IACL,CAAC;IAEkB,MAAM;QACvB,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IACjC,CAAC;CACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ProviderDriver } from "./types.js";
|
|
2
|
+
export type DriverMode = "subprocess" | "api" | "openai" | "grok" | "gemini" | "none";
|
|
3
|
+
export interface DriverFactoryOpts {
|
|
4
|
+
binary: string;
|
|
5
|
+
antBinary: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Create the appropriate driver from a mode string.
|
|
9
|
+
* Returns null for "none" (orchestration disabled).
|
|
10
|
+
*/
|
|
11
|
+
export declare function createDriver(mode: DriverMode, opts: DriverFactoryOpts, log: (msg: string) => void): ProviderDriver | null;
|
|
12
|
+
export { ApiDriver } from "./claude/api.js";
|
|
13
|
+
export { SubprocessDriver } from "./claude/subprocess.js";
|
|
14
|
+
export { GeminiSubprocessDriver } from "./gemini/index.js";
|
|
15
|
+
export { GrokApiDriver } from "./grok/index.js";
|
|
16
|
+
export { OpenAIApiDriver } from "./openai/index.js";
|
|
17
|
+
export type { ProviderDriver, ProviderTaskInput, ProviderTaskOutcome, ProviderTaskResult, } from "./types.js";
|
|
18
|
+
export { toProviderTaskOutcome } from "./types.js";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ApiDriver } from "./claude/api.js";
|
|
2
|
+
import { SubprocessDriver } from "./claude/subprocess.js";
|
|
3
|
+
import { GeminiSubprocessDriver } from "./gemini/index.js";
|
|
4
|
+
import { GrokApiDriver } from "./grok/index.js";
|
|
5
|
+
import { OpenAIApiDriver } from "./openai/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create the appropriate driver from a mode string.
|
|
8
|
+
* Returns null for "none" (orchestration disabled).
|
|
9
|
+
*/
|
|
10
|
+
export function createDriver(mode, opts, log) {
|
|
11
|
+
if (mode === "none")
|
|
12
|
+
return null;
|
|
13
|
+
if (mode === "subprocess")
|
|
14
|
+
return new SubprocessDriver(opts.binary, opts.antBinary, log);
|
|
15
|
+
if (mode === "api")
|
|
16
|
+
return new ApiDriver(log);
|
|
17
|
+
if (mode === "openai")
|
|
18
|
+
return new OpenAIApiDriver(log);
|
|
19
|
+
if (mode === "grok")
|
|
20
|
+
return new GrokApiDriver(log);
|
|
21
|
+
if (mode === "gemini")
|
|
22
|
+
return new GeminiSubprocessDriver(opts.binary === "claude" ? "gemini" : opts.binary, log);
|
|
23
|
+
throw new Error(`Unknown driver mode: ${mode}`);
|
|
24
|
+
}
|
|
25
|
+
export { ApiDriver } from "./claude/api.js";
|
|
26
|
+
export { SubprocessDriver } from "./claude/subprocess.js";
|
|
27
|
+
export { GeminiSubprocessDriver } from "./gemini/index.js";
|
|
28
|
+
export { GrokApiDriver } from "./grok/index.js";
|
|
29
|
+
export { OpenAIApiDriver } from "./openai/index.js";
|
|
30
|
+
export { toProviderTaskOutcome } from "./types.js";
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/drivers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAgBpD;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAgB,EAChB,IAAuB,EACvB,GAA0B;IAE1B,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,IAAI,KAAK,YAAY;QACvB,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAChE,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;IACvD,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;IACnD,IAAI,IAAI,KAAK,QAAQ;QACnB,OAAO,IAAI,sBAAsB,CAC/B,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EACjD,GAAG,CACJ,CAAC;IACJ,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAOpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ProviderDriver, ProviderTaskInput, ProviderTaskResult } from "../types.js";
|
|
2
|
+
export interface OpenAIDriverOpts {
|
|
3
|
+
/** Override API base URL — used by Grok and other OpenAI-compatible endpoints. */
|
|
4
|
+
baseURL?: string;
|
|
5
|
+
/** Default model when input.model is not set. */
|
|
6
|
+
defaultModel?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* OpenAI API driver — streams via chat.completions.create.
|
|
10
|
+
* Dynamic import: openai package is an optional peer dep (not in package.json).
|
|
11
|
+
* Install: npm install openai
|
|
12
|
+
*
|
|
13
|
+
* Limitation: single-turn only — no agentic tool-use loop.
|
|
14
|
+
* providerOptions: { maxTokens?: number, temperature?: number }
|
|
15
|
+
*/
|
|
16
|
+
export declare class OpenAIApiDriver implements ProviderDriver {
|
|
17
|
+
private readonly log;
|
|
18
|
+
private readonly opts;
|
|
19
|
+
readonly name: string;
|
|
20
|
+
constructor(log: (msg: string) => void, opts?: OpenAIDriverOpts);
|
|
21
|
+
run(input: ProviderTaskInput): Promise<ProviderTaskResult>;
|
|
22
|
+
/** Override in subclasses to use a different env var. */
|
|
23
|
+
protected apiKey(): string | undefined;
|
|
24
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
const OUTPUT_CAP = 50 * 1024;
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI API driver — streams via chat.completions.create.
|
|
4
|
+
* Dynamic import: openai package is an optional peer dep (not in package.json).
|
|
5
|
+
* Install: npm install openai
|
|
6
|
+
*
|
|
7
|
+
* Limitation: single-turn only — no agentic tool-use loop.
|
|
8
|
+
* providerOptions: { maxTokens?: number, temperature?: number }
|
|
9
|
+
*/
|
|
10
|
+
export class OpenAIApiDriver {
|
|
11
|
+
log;
|
|
12
|
+
opts;
|
|
13
|
+
name = "openai";
|
|
14
|
+
constructor(log, opts = {}) {
|
|
15
|
+
this.log = log;
|
|
16
|
+
this.opts = opts;
|
|
17
|
+
if (!process.env.OPENAI_API_KEY && !opts.baseURL) {
|
|
18
|
+
throw new Error("OpenAIApiDriver requires OPENAI_API_KEY environment variable");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async run(input) {
|
|
22
|
+
// biome-ignore lint/suspicious/noExplicitAny: dynamic import of optional peer dep
|
|
23
|
+
let OpenAICtor;
|
|
24
|
+
try {
|
|
25
|
+
// biome-ignore lint/suspicious/noExplicitAny: dynamic import
|
|
26
|
+
const mod = await import("openai");
|
|
27
|
+
// biome-ignore lint/suspicious/noExplicitAny: dynamic import
|
|
28
|
+
OpenAICtor = mod.default ?? mod.OpenAI ?? mod;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw new Error("OpenAIApiDriver requires openai — install it with: npm install openai");
|
|
32
|
+
}
|
|
33
|
+
const opts = input.providerOptions ?? {};
|
|
34
|
+
const maxTokens = typeof opts.maxTokens === "number" ? opts.maxTokens : 4096;
|
|
35
|
+
const temperature = typeof opts.temperature === "number" ? opts.temperature : undefined;
|
|
36
|
+
const contextNote = input.contextFiles && input.contextFiles.length > 0
|
|
37
|
+
? `\n\n--- BEGIN CONTEXT FILE LIST ---\n${input.contextFiles
|
|
38
|
+
.map((f) => f.slice(0, 500).replace(/[\x00-\x1f\x7f]/g, ""))
|
|
39
|
+
.join("\n")}\n--- END CONTEXT FILE LIST ---`
|
|
40
|
+
: "";
|
|
41
|
+
const messages = [];
|
|
42
|
+
if (input.systemPrompt) {
|
|
43
|
+
messages.push({ role: "system", content: input.systemPrompt });
|
|
44
|
+
}
|
|
45
|
+
messages.push({ role: "user", content: input.prompt + contextNote });
|
|
46
|
+
const clientOpts = {};
|
|
47
|
+
if (this.opts.baseURL)
|
|
48
|
+
clientOpts.baseURL = this.opts.baseURL;
|
|
49
|
+
// Use provider-specific API key env var if set, fall back to OPENAI_API_KEY
|
|
50
|
+
const apiKey = this.apiKey();
|
|
51
|
+
if (apiKey)
|
|
52
|
+
clientOpts.apiKey = apiKey;
|
|
53
|
+
const client = new OpenAICtor(clientOpts);
|
|
54
|
+
const start = Date.now();
|
|
55
|
+
const model = input.model ?? this.opts.defaultModel ?? "gpt-4o";
|
|
56
|
+
this.log(`[${this.name}] streaming: model=${model} workspace=${input.workspace}`);
|
|
57
|
+
let text = "";
|
|
58
|
+
let firstChunkAt;
|
|
59
|
+
try {
|
|
60
|
+
// biome-ignore lint/suspicious/noExplicitAny: dynamic import shape
|
|
61
|
+
const stream = await client.chat.completions.create({
|
|
62
|
+
model,
|
|
63
|
+
max_tokens: maxTokens,
|
|
64
|
+
...(temperature !== undefined ? { temperature } : {}),
|
|
65
|
+
messages,
|
|
66
|
+
stream: true,
|
|
67
|
+
}, { signal: input.signal });
|
|
68
|
+
// biome-ignore lint/suspicious/noExplicitAny: stream shape from dynamic import
|
|
69
|
+
for await (const chunk of stream) {
|
|
70
|
+
const delta = chunk.choices?.[0]?.delta?.content ?? "";
|
|
71
|
+
if (delta) {
|
|
72
|
+
if (firstChunkAt === undefined)
|
|
73
|
+
firstChunkAt = Date.now();
|
|
74
|
+
text += delta;
|
|
75
|
+
if (text.length <= OUTPUT_CAP) {
|
|
76
|
+
input.onChunk?.(delta);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
const isAbort = (err instanceof Error && err.name === "AbortError") ||
|
|
83
|
+
input.signal.aborted;
|
|
84
|
+
if (isAbort) {
|
|
85
|
+
return {
|
|
86
|
+
text: text.slice(0, OUTPUT_CAP),
|
|
87
|
+
durationMs: Date.now() - start,
|
|
88
|
+
wasAborted: true,
|
|
89
|
+
startupMs: firstChunkAt !== undefined ? firstChunkAt - start : undefined,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
text: text.slice(0, OUTPUT_CAP),
|
|
94
|
+
durationMs: Date.now() - start,
|
|
95
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
text: text.slice(0, OUTPUT_CAP),
|
|
100
|
+
durationMs: Date.now() - start,
|
|
101
|
+
startupMs: firstChunkAt !== undefined ? firstChunkAt - start : undefined,
|
|
102
|
+
providerMeta: { model },
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** Override in subclasses to use a different env var. */
|
|
106
|
+
apiKey() {
|
|
107
|
+
return process.env.OPENAI_API_KEY;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/drivers/openai/index.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC;AAS7B;;;;;;;GAOG;AACH,MAAM,OAAO,eAAe;IAIP;IACA;IAJV,IAAI,GAAW,QAAQ,CAAC;IAEjC,YACmB,GAA0B,EAC1B,OAAyB,EAAE;QAD3B,QAAG,GAAH,GAAG,CAAuB;QAC1B,SAAI,GAAJ,IAAI,CAAuB;QAE5C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CACb,8DAA8D,CAC/D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAwB;QAChC,kFAAkF;QAClF,IAAI,UAAkC,CAAC;QACvC,IAAI,CAAC;YACH,6DAA6D;YAC7D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAe,CAAC,CAAC;YAC1C,6DAA6D;YAC7D,UAAU,GAAI,GAAW,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,uEAAuE,CACxE,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,KAAK,CAAC,eAAe,IAAI,EAAE,CAAC;QACzC,MAAM,SAAS,GACb,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7D,MAAM,WAAW,GACf,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;QAEtE,MAAM,WAAW,GACf,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;YACjD,CAAC,CAAC,wCAAwC,KAAK,CAAC,YAAY;iBACvD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;iBAC3D,IAAI,CAAC,IAAI,CAAC,iCAAiC;YAChD,CAAC,CAAC,EAAE,CAAC;QAET,MAAM,QAAQ,GAA6C,EAAE,CAAC;QAC9D,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;QACjE,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC,CAAC;QAErE,MAAM,UAAU,GAA4B,EAAE,CAAC;QAC/C,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;QAC9D,4EAA4E;QAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC7B,IAAI,MAAM;YAAE,UAAU,CAAC,MAAM,GAAG,MAAM,CAAC;QAEvC,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,QAAQ,CAAC;QAEhE,IAAI,CAAC,GAAG,CACN,IAAI,IAAI,CAAC,IAAI,sBAAsB,KAAK,cAAc,KAAK,CAAC,SAAS,EAAE,CACxE,CAAC;QAEF,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,YAAgC,CAAC;QAErC,IAAI,CAAC;YACH,mEAAmE;YACnE,MAAM,MAAM,GAAG,MAAO,MAAM,CAAC,IAAI,CAAC,WAAmB,CAAC,MAAM,CAC1D;gBACE,KAAK;gBACL,UAAU,EAAE,SAAS;gBACrB,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrD,QAAQ;gBACR,MAAM,EAAE,IAAI;aACb,EACD,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CACzB,CAAC;YAEF,+EAA+E;YAC/E,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAA4B,EAAE,CAAC;gBACvD,MAAM,KAAK,GAAW,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC;gBAC/D,IAAI,KAAK,EAAE,CAAC;oBACV,IAAI,YAAY,KAAK,SAAS;wBAAE,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;oBAC1D,IAAI,IAAI,KAAK,CAAC;oBACd,IAAI,IAAI,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;wBAC9B,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;oBACzB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GACX,CAAC,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC;gBACnD,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;YACvB,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO;oBACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;oBAC/B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;oBAC9B,UAAU,EAAE,IAAI;oBAChB,SAAS,EACP,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS;iBAChE,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;gBAC/B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;gBAC9B,YAAY,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aAC/D,CAAC;QACJ,CAAC;QAED,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC;YAC/B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;YAC9B,SAAS,EAAE,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS;YACxE,YAAY,EAAE,EAAE,KAAK,EAAE;SACxB,CAAC;IACJ,CAAC;IAED,yDAAyD;IAC/C,MAAM;QACd,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IACpC,CAAC;CACF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-neutral driver types.
|
|
3
|
+
* All drivers implement ProviderDriver; Claude-specific fields go in providerOptions.
|
|
4
|
+
*/
|
|
5
|
+
export interface ProviderTaskInput {
|
|
6
|
+
prompt: string;
|
|
7
|
+
/** Working directory / context hint passed as cwd to the subprocess or API call. */
|
|
8
|
+
workspace: string;
|
|
9
|
+
timeoutMs: number;
|
|
10
|
+
signal: AbortSignal;
|
|
11
|
+
onChunk?: (chunk: string) => void;
|
|
12
|
+
/** Informational list of paths; driver decides how to surface them. */
|
|
13
|
+
contextFiles?: string[];
|
|
14
|
+
/** Provider-specific model ID (e.g. "claude-sonnet-4-6", "gemini-2.5-pro"). */
|
|
15
|
+
model?: string;
|
|
16
|
+
systemPrompt?: string;
|
|
17
|
+
/** Startup timeout: abort if no output arrives within this many ms of spawn. */
|
|
18
|
+
startupTimeoutMs?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Provider-specific overrides — driver may ignore unknown keys.
|
|
21
|
+
* Claude subprocess: { effort, fallbackModel, maxBudgetUsd, useAnt }
|
|
22
|
+
* Gemini subprocess: { binary }
|
|
23
|
+
* OpenAI API: { maxTokens, temperature }
|
|
24
|
+
*/
|
|
25
|
+
providerOptions?: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
export interface ProviderTaskResult {
|
|
28
|
+
text: string;
|
|
29
|
+
durationMs: number;
|
|
30
|
+
startupMs?: number;
|
|
31
|
+
wasAborted?: boolean;
|
|
32
|
+
/** Set when the provider signals an error (replaces exitCode for API drivers). */
|
|
33
|
+
errorMessage?: string;
|
|
34
|
+
/** Tokens used, resolved model, etc. Driver-specific. */
|
|
35
|
+
providerMeta?: Record<string, unknown>;
|
|
36
|
+
exitCode?: number;
|
|
37
|
+
stderrTail?: string;
|
|
38
|
+
startupTimedOut?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export type ProviderTaskOutcome = {
|
|
41
|
+
outcome: "done";
|
|
42
|
+
text: string;
|
|
43
|
+
durationMs: number;
|
|
44
|
+
startupMs?: number;
|
|
45
|
+
providerMeta?: Record<string, unknown>;
|
|
46
|
+
} | {
|
|
47
|
+
outcome: "error";
|
|
48
|
+
errorMessage: string;
|
|
49
|
+
durationMs: number;
|
|
50
|
+
} | {
|
|
51
|
+
outcome: "aborted";
|
|
52
|
+
cancelKind: "startup_timeout" | "timeout" | "user";
|
|
53
|
+
durationMs: number;
|
|
54
|
+
};
|
|
55
|
+
export interface ProviderDriver {
|
|
56
|
+
readonly name: string;
|
|
57
|
+
/** Primary entry point. Must resolve; never reject (swallow errors into result). */
|
|
58
|
+
run(input: ProviderTaskInput): Promise<ProviderTaskResult>;
|
|
59
|
+
/** Optional: discriminated-union variant. Default impl wraps run(). */
|
|
60
|
+
runOutcome?(input: ProviderTaskInput): Promise<ProviderTaskOutcome>;
|
|
61
|
+
/** Optional: long-lived session lifecycle (server-mode drivers). */
|
|
62
|
+
spawnForSession?(sessionId: string): Promise<void>;
|
|
63
|
+
killForSession?(sessionId: string): void;
|
|
64
|
+
/** Called once on bridge shutdown. Clean up connections, temp files. */
|
|
65
|
+
destroy?(): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
export declare function toProviderTaskOutcome(result: ProviderTaskResult, cancelReason?: "timeout" | "startup_timeout" | "user" | "shutdown"): ProviderTaskOutcome;
|
|
68
|
+
/**
|
|
69
|
+
* @deprecated Use ProviderDriver. IClaudeDriver is a backward-compat alias.
|
|
70
|
+
* Will be removed in a future minor version.
|
|
71
|
+
*/
|
|
72
|
+
export type IClaudeDriver = ProviderDriver;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-neutral driver types.
|
|
3
|
+
* All drivers implement ProviderDriver; Claude-specific fields go in providerOptions.
|
|
4
|
+
*/
|
|
5
|
+
export function toProviderTaskOutcome(result, cancelReason) {
|
|
6
|
+
if (result.wasAborted) {
|
|
7
|
+
const cancelKind = result.startupTimedOut || cancelReason === "startup_timeout"
|
|
8
|
+
? "startup_timeout"
|
|
9
|
+
: cancelReason === "timeout"
|
|
10
|
+
? "timeout"
|
|
11
|
+
: "user";
|
|
12
|
+
return { outcome: "aborted", cancelKind, durationMs: result.durationMs };
|
|
13
|
+
}
|
|
14
|
+
if (result.errorMessage ||
|
|
15
|
+
(result.exitCode !== undefined && result.exitCode !== 0)) {
|
|
16
|
+
return {
|
|
17
|
+
outcome: "error",
|
|
18
|
+
errorMessage: result.errorMessage ?? `exit code ${result.exitCode}`,
|
|
19
|
+
durationMs: result.durationMs,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
outcome: "done",
|
|
24
|
+
text: result.text,
|
|
25
|
+
durationMs: result.durationMs,
|
|
26
|
+
startupMs: result.startupMs,
|
|
27
|
+
providerMeta: result.providerMeta,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/drivers/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoEH,MAAM,UAAU,qBAAqB,CACnC,MAA0B,EAC1B,YAAkE;IAElE,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,MAAM,UAAU,GACd,MAAM,CAAC,eAAe,IAAI,YAAY,KAAK,iBAAiB;YAC1D,CAAC,CAAC,iBAAiB;YACnB,CAAC,CAAC,YAAY,KAAK,SAAS;gBAC1B,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,MAAM,CAAC;QACf,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC;IAC3E,CAAC;IACD,IACE,MAAM,CAAC,YAAY;QACnB,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,CAAC,EACxD,CAAC;QACD,OAAO;YACL,OAAO,EAAE,OAAO;YAChB,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,aAAa,MAAM,CAAC,QAAQ,EAAE;YACnE,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC;IACJ,CAAC;IACD,OAAO;QACL,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,YAAY,EAAE,MAAM,CAAC,YAAY;KAClC,CAAC;AACJ,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Uses Node 20.6+ native dotenv loader; falls back to manual parse for older Node.
|
|
4
4
|
{
|
|
5
5
|
const { fileURLToPath: _fileURLToPath } = await import("node:url");
|
|
6
|
-
const envPath = _fileURLToPath(new URL("
|
|
6
|
+
const envPath = _fileURLToPath(new URL("../.env", import.meta.url));
|
|
7
7
|
try {
|
|
8
8
|
const { readFileSync, existsSync } = await import("node:fs");
|
|
9
9
|
if (existsSync(envPath)) {
|