@gobing-ai/knowledge-kit 0.0.19 → 0.0.22
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/.claude-plugin/marketplace.json +1 -1
- package/dist/index.js +161 -142
- package/package.json +1 -1
- package/plugins/generations/content-gen/dist/index.js +20 -3
- package/plugins/generations/core-facts-gen/dist/index.js +20 -3
- package/plugins/generations/daily-article-gen/dist/index.js +20 -3
- package/plugins/generations/dailynews-gen/dist/index.js +29 -4
- package/plugins/generations/dailynews-gen/src/script-builder.ts +19 -1
- package/plugins/generations/episode-plan-gen/dist/index.js +20 -3
- package/plugins/generations/image-gen/dist/index.js +147 -69
- package/plugins/generations/image-gen/src/presets.ts +2 -2
- package/plugins/generations/image-gen/src/providers/agnes.ts +6 -2
- package/plugins/generations/image-gen/src/providers/azure.ts +6 -2
- package/plugins/generations/image-gen/src/providers/dashscope.ts +10 -3
- package/plugins/generations/image-gen/src/providers/google.ts +70 -29
- package/plugins/generations/image-gen/src/providers/huggingface.ts +3 -0
- package/plugins/generations/image-gen/src/providers/jimeng.ts +9 -2
- package/plugins/generations/image-gen/src/providers/minimax.ts +10 -2
- package/plugins/generations/image-gen/src/providers/openai.ts +9 -3
- package/plugins/generations/image-gen/src/providers/openrouter.ts +16 -4
- package/plugins/generations/image-gen/src/providers/replicate.ts +13 -3
- package/plugins/generations/image-gen/src/providers/seedream.ts +4 -1
- package/plugins/generations/image-gen/src/providers/timeouts.ts +14 -0
- package/plugins/generations/image-gen/src/providers/types.ts +10 -0
- package/plugins/generations/image-gen/src/providers/zai.ts +4 -1
- package/plugins/generations/news-report-gen/dist/index.js +20 -3
- package/plugins/generations/omni-voice-gen/src/omni_voice_gen/pipeline.py +13 -5
- package/plugins/generations/omni-voice-gen/src/omni_voice_gen/qc.py +23 -15
- package/plugins/generations/voice-gen/dist/index.js +36 -10
- package/plugins/generations/voice-gen/src/voicebox-client.ts +18 -4
- package/plugins/generations/voice-gen/src/voicebox-server.ts +2 -1
- package/plugins/ingestions/aihot-ingest/dist/index.js +26 -6
- package/plugins/ingestions/aihot-ingest/plugin.json +1 -1
- package/plugins/ingestions/aihot-ingest/src/client.ts +5 -0
- package/plugins/ingestions/aihot-ingest/src/rss.ts +12 -2
- package/plugins/ingestions/horizon-ingest/dist/index.js +20 -3
- package/plugins/ingestions/last30days-ingest/dist/index.js +20 -3
- package/plugins/ingestions/web-search/dist/index.js +22 -3
- package/plugins/ingestions/web-search/src/index.ts +4 -0
- package/plugins/kk/commands/workflow-run.md +20 -6
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/scripts/itc-stages.ts +563 -0
- package/plugins/kk/scripts/kk-workflow-stages.ts +125 -18
- package/plugins/kk/scripts/render-md.ts +7 -1
- package/plugins/kk/skills/article-adapt/SKILL.md +85 -0
- package/plugins/kk/workflows/kk-daily-ai-voice.yaml +26 -16
- package/plugins/kk/workflows/kk-itc.yaml +461 -12
- package/plugins/publishings/emdash-pub/dist/index.js +76 -19
- package/plugins/publishings/emdash-pub/src/index.ts +4 -0
- package/plugins/publishings/infoq-pub/dist/index.js +74 -21
- package/plugins/publishings/juejin-pub/dist/index.js +74 -21
- package/plugins/publishings/medium-pub/dist/index.js +77 -19
- package/plugins/publishings/medium-pub/src/index.ts +5 -0
- package/plugins/publishings/podcast-pub/dist/index.js +130 -34
- package/plugins/publishings/podcast-pub/src/index.ts +20 -5
- package/plugins/publishings/podcast-pub/src/map.ts +11 -0
- package/plugins/publishings/podcast-pub/src/show-notes.ts +66 -13
- package/plugins/publishings/qiita-pub/dist/index.js +75 -18
- package/plugins/publishings/qiita-pub/src/index.ts +4 -0
- package/plugins/publishings/substack-pub/dist/index.js +74 -21
- package/plugins/publishings/surfdash-pub/dist/index.js +99 -62
- package/plugins/publishings/surfdash-pub/src/index.ts +60 -19
- package/plugins/publishings/wechatmp-pub/dist/index.js +79 -22
- package/plugins/publishings/wechatmp-pub/src/index.ts +12 -3
- package/plugins/publishings/x-pub/dist/index.js +56 -37
- package/plugins/publishings/x-pub/src/index.ts +4 -0
- package/plugins/publishings/xhs-pub/dist/index.js +74 -21
- package/plugins/publishings/zenn-pub/dist/index.js +103 -25
- package/plugins/publishings/zenn-pub/src/index.ts +43 -9
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { extname } from 'node:path';
|
|
2
2
|
import { readBytes } from '../bytes';
|
|
3
3
|
import { extractImageFromResponse, getOpenAISize, type OpenAIImageResponse } from './openai';
|
|
4
|
+
import { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
4
5
|
import type { ImageProvider, ImageRequest, ImageResult, ProviderFactory, ProviderOptions } from './types';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -77,6 +78,7 @@ export function validateReferenceImages(referenceImages: readonly string[]): voi
|
|
|
77
78
|
|
|
78
79
|
export const createAzure: ProviderFactory = (options?: ProviderOptions): ImageProvider => {
|
|
79
80
|
const fetchFn = options?.fetch ?? fetch;
|
|
81
|
+
const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
|
|
80
82
|
const env = options?.env ?? process.env;
|
|
81
83
|
// Azure's own env-precedence for a default model: explicit deployment, then the base URL,
|
|
82
84
|
// then the frozen 'gpt-image-2' (matches the baoyu getDefaultModel chain; spec facts unchanged).
|
|
@@ -135,17 +137,19 @@ export const createAzure: ProviderFactory = (options?: ProviderOptions): ImagePr
|
|
|
135
137
|
method: 'POST',
|
|
136
138
|
headers: { 'api-key': apiKey },
|
|
137
139
|
body: form,
|
|
140
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
138
141
|
});
|
|
139
142
|
if (!res.ok) throw new Error(`Azure OpenAI edits API error: ${await res.text()}`);
|
|
140
|
-
return extractImageFromResponse((await res.json()) as OpenAIImageResponse, fetchFn);
|
|
143
|
+
return extractImageFromResponse((await res.json()) as OpenAIImageResponse, fetchFn, timeoutMs);
|
|
141
144
|
}
|
|
142
145
|
const res = await fetchFn(buildURL(endpoint, deployment, '/images/generations', env), {
|
|
143
146
|
method: 'POST',
|
|
144
147
|
headers: { 'content-type': 'application/json', 'api-key': apiKey },
|
|
145
148
|
body: JSON.stringify({ prompt: req.prompt, size, n: 1, quality: getAzureQuality(req.quality) }),
|
|
149
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
146
150
|
});
|
|
147
151
|
if (!res.ok) throw new Error(`Azure OpenAI API error: ${await res.text()}`);
|
|
148
|
-
return extractImageFromResponse((await res.json()) as OpenAIImageResponse, fetchFn);
|
|
152
|
+
return extractImageFromResponse((await res.json()) as OpenAIImageResponse, fetchFn, timeoutMs);
|
|
149
153
|
})();
|
|
150
154
|
return { bytes, extension: 'png', provider: 'azure', model: req.model };
|
|
151
155
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { echoError } from '@gobing-ai/ts-utils';
|
|
3
3
|
import { refToDataUri } from './refs';
|
|
4
|
+
import { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
4
5
|
import type { ImageProvider, ImageRequest, ImageResult, ProviderFactory, ProviderOptions } from './types';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -389,7 +390,11 @@ interface DashScopeResponse {
|
|
|
389
390
|
};
|
|
390
391
|
}
|
|
391
392
|
|
|
392
|
-
async function extractImageFromResponse(
|
|
393
|
+
async function extractImageFromResponse(
|
|
394
|
+
result: DashScopeResponse,
|
|
395
|
+
fetchFn: typeof fetch,
|
|
396
|
+
timeoutMs: number = PROVIDER_REQUEST_TIMEOUT_MS,
|
|
397
|
+
): Promise<Uint8Array> {
|
|
393
398
|
let imageData: string | null = null;
|
|
394
399
|
if (result.output?.result_image !== undefined) {
|
|
395
400
|
imageData = result.output.result_image;
|
|
@@ -403,7 +408,7 @@ async function extractImageFromResponse(result: DashScopeResponse, fetchFn: type
|
|
|
403
408
|
}
|
|
404
409
|
if (imageData === null) throw new Error('No image in response');
|
|
405
410
|
if (imageData.startsWith('http://') || imageData.startsWith('https://')) {
|
|
406
|
-
const imgRes = await fetchFn(imageData);
|
|
411
|
+
const imgRes = await fetchFn(imageData, { signal: AbortSignal.timeout(timeoutMs) });
|
|
407
412
|
if (!imgRes.ok) throw new Error('Failed to download image');
|
|
408
413
|
return new Uint8Array(await imgRes.arrayBuffer());
|
|
409
414
|
}
|
|
@@ -412,6 +417,7 @@ async function extractImageFromResponse(result: DashScopeResponse, fetchFn: type
|
|
|
412
417
|
|
|
413
418
|
export const createDashscope: ProviderFactory = (options?: ProviderOptions): ImageProvider => {
|
|
414
419
|
const fetchFn = options?.fetch ?? fetch;
|
|
420
|
+
const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
|
|
415
421
|
const env = options?.env ?? process.env;
|
|
416
422
|
const readEnv = (key: string): string => env[key] ?? '';
|
|
417
423
|
const supportsRef = (model: string): boolean => model.includes('wan2.7');
|
|
@@ -476,9 +482,10 @@ export const createDashscope: ProviderFactory = (options?: ProviderOptions): Ima
|
|
|
476
482
|
method: 'POST',
|
|
477
483
|
headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },
|
|
478
484
|
body: JSON.stringify(body),
|
|
485
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
479
486
|
});
|
|
480
487
|
if (!res.ok) throw new Error(`DashScope API error (${res.status}): ${await res.text()}`);
|
|
481
|
-
const bytes = await extractImageFromResponse((await res.json()) as DashScopeResponse, fetchFn);
|
|
488
|
+
const bytes = await extractImageFromResponse((await res.json()) as DashScopeResponse, fetchFn, timeoutMs);
|
|
482
489
|
return { bytes, extension: 'png', provider: 'dashscope', model: req.model };
|
|
483
490
|
},
|
|
484
491
|
};
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { execFileSync } from 'node:child_process';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { createNodeFileSystem } from '@gobing-ai/ts-runtime';
|
|
3
7
|
import { readBytes } from '../bytes';
|
|
4
8
|
import { mimeForPath } from './refs';
|
|
9
|
+
import { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
5
10
|
import type { ImageProvider, ImageRequest, ImageResult, ProviderFactory, ProviderOptions } from './types';
|
|
6
11
|
|
|
7
12
|
/**
|
|
@@ -112,6 +117,25 @@ function getHttpProxy(readEnv: (key: string) => string): string | null {
|
|
|
112
117
|
);
|
|
113
118
|
}
|
|
114
119
|
|
|
120
|
+
/**
|
|
121
|
+
* curl config-file quoting: backslash-escape `\` and `"` inside a double-quoted value.
|
|
122
|
+
* curl's config parser is not a shell, but it does honour these two escapes.
|
|
123
|
+
*/
|
|
124
|
+
const curlQuote = (s: string): string => `"${s.replace(/[\\"]/g, '\\$&')}"`;
|
|
125
|
+
|
|
126
|
+
/** Replaces every secret with `***`; empty entries are skipped so `''` cannot mangle the text. */
|
|
127
|
+
const redact = (s: string, secrets: string[]): string =>
|
|
128
|
+
secrets.filter((x) => x !== '').reduce((acc, x) => acc.replaceAll(x, '***'), s);
|
|
129
|
+
|
|
130
|
+
/** Decoded password from a proxy URL, or '' when the URL carries none or does not parse. */
|
|
131
|
+
function proxyPassword(proxy: string): string {
|
|
132
|
+
try {
|
|
133
|
+
return decodeURIComponent(new URL(proxy).password);
|
|
134
|
+
} catch {
|
|
135
|
+
return '';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
115
139
|
interface GeminiResponse {
|
|
116
140
|
candidates?: Array<{ content?: { parts?: Array<{ inlineData?: { data?: string } }> } }>;
|
|
117
141
|
}
|
|
@@ -123,6 +147,7 @@ interface ImagenResponse {
|
|
|
123
147
|
|
|
124
148
|
export const createGoogle: ProviderFactory = (options?: ProviderOptions): ImageProvider => {
|
|
125
149
|
const fetchFn = options?.fetch ?? fetch;
|
|
150
|
+
const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
|
|
126
151
|
const env = options?.env ?? process.env;
|
|
127
152
|
const readEnv = (key: string): string => env[key] ?? '';
|
|
128
153
|
const refModels = [
|
|
@@ -143,35 +168,50 @@ export const createGoogle: ProviderFactory = (options?: ProviderOptions): ImageP
|
|
|
143
168
|
const proxy = getHttpProxy(readEnv);
|
|
144
169
|
// Bun's fetch drops long-lived proxied sockets; upstream works around it with curl (0115 port).
|
|
145
170
|
if (proxy !== null && options?.fetch === undefined) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
// Secrets stay out of argv: curl reads the proxy and the API key from a config file
|
|
172
|
+
// (`-K <path>`), and the request body arrives on stdin (`-d @-`). `execFileSync` embeds the
|
|
173
|
+
// full argv in `error.message`, so `-x <proxy>` / `-H 'x-goog-api-key: …'` would leak both
|
|
174
|
+
// the key and the proxy password into logs. `-sS` (not `-s`) keeps curl's own diagnostic on
|
|
175
|
+
// stderr, so `details` no longer falls back to that argv-bearing message.
|
|
176
|
+
//
|
|
177
|
+
// File IO goes through the `@gobing-ai/ts-runtime` seam (`no-direct-fs-io`): the seam is
|
|
178
|
+
// text-only with no `mode` argument, and the file lives in `os.tmpdir()`, which is a
|
|
179
|
+
// per-user directory (0700 on macOS).
|
|
180
|
+
const configPath = join(tmpdir(), `kk-image-gen-${randomUUID()}.curlrc`);
|
|
181
|
+
const config = `proxy = ${curlQuote(proxy)}\nheader = ${curlQuote(`x-goog-api-key: ${apiKey}`)}\n`;
|
|
182
|
+
const fileSystem = createNodeFileSystem();
|
|
183
|
+
await fileSystem.writeFile(configPath, config);
|
|
184
|
+
let result: string;
|
|
185
|
+
try {
|
|
186
|
+
result = execFileSync(
|
|
187
|
+
'curl',
|
|
188
|
+
[
|
|
189
|
+
'-sS',
|
|
190
|
+
'--connect-timeout',
|
|
191
|
+
'30',
|
|
192
|
+
'--max-time',
|
|
193
|
+
'300',
|
|
194
|
+
'-K',
|
|
195
|
+
configPath,
|
|
196
|
+
'-H',
|
|
197
|
+
'Content-Type: application/json',
|
|
198
|
+
'-d',
|
|
199
|
+
'@-',
|
|
200
|
+
url,
|
|
201
|
+
],
|
|
202
|
+
{ input: JSON.stringify(body), encoding: 'utf8', timeout: 310_000 },
|
|
203
|
+
);
|
|
204
|
+
} catch (error: unknown) {
|
|
205
|
+
const e = error as { message?: string; stderr?: string | Buffer };
|
|
206
|
+
const details =
|
|
207
|
+
(typeof e.stderr === 'string' ? e.stderr.trim() : '') || e.message || 'curl request failed';
|
|
208
|
+
// Redact the raw `user:pass@host` form as well as the decoded password.
|
|
209
|
+
throw new Error(
|
|
210
|
+
`Google API request failed via curl: ${redact(details, [apiKey, proxyPassword(proxy), proxy])}`,
|
|
211
|
+
);
|
|
212
|
+
} finally {
|
|
213
|
+
await fileSystem.deleteFile(configPath);
|
|
214
|
+
}
|
|
175
215
|
const parsed = JSON.parse(result) as T & { error?: { code?: string; message?: string } };
|
|
176
216
|
if (parsed.error !== undefined) {
|
|
177
217
|
throw new Error(`Google API error (${parsed.error.code}): ${parsed.error.message}`);
|
|
@@ -182,6 +222,7 @@ export const createGoogle: ProviderFactory = (options?: ProviderOptions): ImageP
|
|
|
182
222
|
method: 'POST',
|
|
183
223
|
headers: { 'content-type': 'application/json', 'x-goog-api-key': apiKey },
|
|
184
224
|
body: JSON.stringify(body),
|
|
225
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
185
226
|
});
|
|
186
227
|
if (!res.ok) {
|
|
187
228
|
const err = await res.text();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
1
2
|
import type { ImageProvider, ImageRequest, ImageResult, ProviderFactory, ProviderOptions } from './types';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -25,6 +26,7 @@ export const buildPayload = (
|
|
|
25
26
|
|
|
26
27
|
export const createHuggingface: ProviderFactory = (options?: ProviderOptions): ImageProvider => {
|
|
27
28
|
const fetchFn = options?.fetch ?? fetch;
|
|
29
|
+
const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
|
|
28
30
|
const env = options?.env ?? process.env;
|
|
29
31
|
const readEnv = (key: string): string => env[key] ?? '';
|
|
30
32
|
|
|
@@ -44,6 +46,7 @@ export const createHuggingface: ProviderFactory = (options?: ProviderOptions): I
|
|
|
44
46
|
method: 'POST',
|
|
45
47
|
headers: { authorization: `Bearer ${token}`, 'content-type': 'application/json' },
|
|
46
48
|
body: JSON.stringify(buildPayload(req)),
|
|
49
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
47
50
|
});
|
|
48
51
|
if (!res.ok) {
|
|
49
52
|
const text = (await res.text()).slice(0, 200);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as crypto from 'node:crypto';
|
|
2
|
+
import { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
2
3
|
import type { ImageProvider, ImageRequest, ImageResult, ProviderFactory, ProviderOptions } from './types';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -142,6 +143,7 @@ interface JimengTaskResponse {
|
|
|
142
143
|
|
|
143
144
|
export const createJimeng: ProviderFactory = (options?: ProviderOptions): ImageProvider => {
|
|
144
145
|
const fetchFn = options?.fetch ?? fetch;
|
|
146
|
+
const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
|
|
145
147
|
const env = options?.env ?? process.env;
|
|
146
148
|
const readEnv = (key: string): string => env[key] ?? '';
|
|
147
149
|
|
|
@@ -170,7 +172,12 @@ export const createJimeng: ProviderFactory = (options?: ProviderOptions): ImageP
|
|
|
170
172
|
'cv',
|
|
171
173
|
endpoint.canonicalUri,
|
|
172
174
|
);
|
|
173
|
-
return fetchFn(endpoint.url, {
|
|
175
|
+
return fetchFn(endpoint.url, {
|
|
176
|
+
method: 'POST',
|
|
177
|
+
headers: { ...headers, authorization },
|
|
178
|
+
body,
|
|
179
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
180
|
+
});
|
|
174
181
|
}
|
|
175
182
|
|
|
176
183
|
async function submitTask(
|
|
@@ -214,7 +221,7 @@ export const createJimeng: ProviderFactory = (options?: ProviderOptions): ImageP
|
|
|
214
221
|
}
|
|
215
222
|
if (status === 'done' && image_urls !== undefined && image_urls.length > 0) {
|
|
216
223
|
const url = image_urls[0] as string;
|
|
217
|
-
const imgRes = await fetchFn(url);
|
|
224
|
+
const imgRes = await fetchFn(url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
218
225
|
if (!imgRes.ok) throw new Error(`Failed to download image from ${url}`);
|
|
219
226
|
return new Uint8Array(await imgRes.arrayBuffer());
|
|
220
227
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { readBytes } from '../bytes';
|
|
3
3
|
import { mimeForPath } from './refs';
|
|
4
|
+
import { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
4
5
|
import type { ImageProvider, ImageRequest, ImageResult, ProviderFactory, ProviderOptions } from './types';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -117,6 +118,7 @@ export async function buildSubjectReference(referenceImages: string[]): Promise<
|
|
|
117
118
|
export async function extractImageFromResponse(
|
|
118
119
|
result: MinimaxResponse,
|
|
119
120
|
fetchFn: typeof fetch = fetch,
|
|
121
|
+
timeoutMs: number = PROVIDER_REQUEST_TIMEOUT_MS,
|
|
120
122
|
): Promise<Uint8Array> {
|
|
121
123
|
const baseResp = result.base_resp;
|
|
122
124
|
if (baseResp?.status_code !== undefined && baseResp.status_code !== 0) {
|
|
@@ -126,7 +128,7 @@ export async function extractImageFromResponse(
|
|
|
126
128
|
if (base64Image !== undefined) return Uint8Array.from(Buffer.from(base64Image, 'base64'));
|
|
127
129
|
const url = result.data?.image_urls?.[0];
|
|
128
130
|
if (url !== undefined) {
|
|
129
|
-
const response = await fetchFn(url);
|
|
131
|
+
const response = await fetchFn(url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
130
132
|
if (!response.ok) throw new Error(`Failed to download image from MiniMax: ${response.status}`);
|
|
131
133
|
return new Uint8Array(await response.arrayBuffer());
|
|
132
134
|
}
|
|
@@ -135,6 +137,7 @@ export async function extractImageFromResponse(
|
|
|
135
137
|
|
|
136
138
|
export const createMinimax: ProviderFactory = (options?: ProviderOptions): ImageProvider => {
|
|
137
139
|
const fetchFn = options?.fetch ?? fetch;
|
|
140
|
+
const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
|
|
138
141
|
const env = options?.env ?? process.env;
|
|
139
142
|
const readEnv = (key: string): string => env[key] ?? '';
|
|
140
143
|
|
|
@@ -160,11 +163,16 @@ export const createMinimax: ProviderFactory = (options?: ProviderOptions): Image
|
|
|
160
163
|
method: 'POST',
|
|
161
164
|
headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },
|
|
162
165
|
body: JSON.stringify(body),
|
|
166
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
163
167
|
});
|
|
164
168
|
if (!response.ok) {
|
|
165
169
|
throw new Error(`MiniMax API error (${response.status}): ${await response.text()}`);
|
|
166
170
|
}
|
|
167
|
-
const bytes = await extractImageFromResponse(
|
|
171
|
+
const bytes = await extractImageFromResponse(
|
|
172
|
+
(await response.json()) as MinimaxResponse,
|
|
173
|
+
fetchFn,
|
|
174
|
+
timeoutMs,
|
|
175
|
+
);
|
|
168
176
|
return { bytes, extension: 'jpg', provider: 'minimax', model: req.model };
|
|
169
177
|
},
|
|
170
178
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { basename } from 'node:path';
|
|
3
3
|
import { readBytes } from '../bytes';
|
|
4
|
+
import { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
4
5
|
import type { ImageProvider, ImageRequest, ImageResult, ProviderFactory, ProviderOptions } from './types';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -207,13 +208,14 @@ export function getMimeType(filename: string): string {
|
|
|
207
208
|
export async function extractImageFromResponse(
|
|
208
209
|
result: OpenAIImageResponse,
|
|
209
210
|
fetchFn: typeof fetch = fetch,
|
|
211
|
+
timeoutMs: number = PROVIDER_REQUEST_TIMEOUT_MS,
|
|
210
212
|
): Promise<Uint8Array> {
|
|
211
213
|
const img = result.data[0];
|
|
212
214
|
if (img?.b64_json !== undefined && img.b64_json !== '') {
|
|
213
215
|
return Uint8Array.from(Buffer.from(img.b64_json, 'base64'));
|
|
214
216
|
}
|
|
215
217
|
if (img?.url !== undefined) {
|
|
216
|
-
const imgRes = await fetchFn(img.url);
|
|
218
|
+
const imgRes = await fetchFn(img.url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
217
219
|
if (!imgRes.ok) throw new Error('Failed to download image');
|
|
218
220
|
return new Uint8Array(await imgRes.arrayBuffer());
|
|
219
221
|
}
|
|
@@ -222,6 +224,7 @@ export async function extractImageFromResponse(
|
|
|
222
224
|
|
|
223
225
|
export const createOpenai: ProviderFactory = (options?: ProviderOptions): ImageProvider => {
|
|
224
226
|
const fetchFn = options?.fetch ?? fetch;
|
|
227
|
+
const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
|
|
225
228
|
const env = options?.env ?? process.env;
|
|
226
229
|
const readEnv = (key: string): string => env[key] ?? '';
|
|
227
230
|
const supportsRef = (model: string): boolean => model.includes('gpt-image');
|
|
@@ -255,6 +258,7 @@ export const createOpenai: ProviderFactory = (options?: ProviderOptions): ImageP
|
|
|
255
258
|
method: 'POST',
|
|
256
259
|
headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },
|
|
257
260
|
body: JSON.stringify({ model: req.model, messages: [{ role: 'user', content: req.prompt }] }),
|
|
261
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
258
262
|
});
|
|
259
263
|
if (!chatRes.ok) throw new Error(`OpenAI API error: ${await chatRes.text()}`);
|
|
260
264
|
const content =
|
|
@@ -301,17 +305,19 @@ export const createOpenai: ProviderFactory = (options?: ProviderOptions): ImageP
|
|
|
301
305
|
method: 'POST',
|
|
302
306
|
headers: { authorization: `Bearer ${apiKey}` },
|
|
303
307
|
body: form,
|
|
308
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
304
309
|
});
|
|
305
310
|
if (!res.ok) throw new Error(`OpenAI edits API error: ${await res.text()}`);
|
|
306
|
-
return extractImageFromResponse((await res.json()) as OpenAIImageResponse, fetchFn);
|
|
311
|
+
return extractImageFromResponse((await res.json()) as OpenAIImageResponse, fetchFn, timeoutMs);
|
|
307
312
|
}
|
|
308
313
|
const res = await fetchFn(`${baseURL}/images/generations`, {
|
|
309
314
|
method: 'POST',
|
|
310
315
|
headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },
|
|
311
316
|
body: JSON.stringify(buildOpenAIGenerationsBody(req.prompt, req.model, args)),
|
|
317
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
312
318
|
});
|
|
313
319
|
if (!res.ok) throw new Error(`OpenAI API error: ${await res.text()}`);
|
|
314
|
-
return extractImageFromResponse((await res.json()) as OpenAIImageResponse, fetchFn);
|
|
320
|
+
return extractImageFromResponse((await res.json()) as OpenAIImageResponse, fetchFn, timeoutMs);
|
|
315
321
|
})();
|
|
316
322
|
return { bytes, extension: 'png', provider: 'openai', model: req.model };
|
|
317
323
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { refToDataUri } from './refs';
|
|
3
|
+
import { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
3
4
|
import type { ImageProvider, ImageRequest, ImageResult, ProviderFactory, ProviderOptions } from './types';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -137,11 +138,15 @@ function decodeDataUrl(value: string): Uint8Array | null {
|
|
|
137
138
|
return Uint8Array.from(Buffer.from(match[1] as string, 'base64'));
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
async function downloadImage(
|
|
141
|
+
async function downloadImage(
|
|
142
|
+
value: string,
|
|
143
|
+
fetchFn: typeof fetch,
|
|
144
|
+
timeoutMs: number = PROVIDER_REQUEST_TIMEOUT_MS,
|
|
145
|
+
): Promise<Uint8Array> {
|
|
141
146
|
const inline = decodeDataUrl(value);
|
|
142
147
|
if (inline !== null) return inline;
|
|
143
148
|
if (value.startsWith('http://') || value.startsWith('https://')) {
|
|
144
|
-
const response = await fetchFn(value);
|
|
149
|
+
const response = await fetchFn(value, { signal: AbortSignal.timeout(timeoutMs) });
|
|
145
150
|
if (!response.ok) throw new Error(`Failed to download OpenRouter image: ${response.status}`);
|
|
146
151
|
return new Uint8Array(await response.arrayBuffer());
|
|
147
152
|
}
|
|
@@ -151,12 +156,13 @@ async function downloadImage(value: string, fetchFn: typeof fetch): Promise<Uint
|
|
|
151
156
|
export async function extractImageFromResponse(
|
|
152
157
|
result: OpenRouterResponse,
|
|
153
158
|
fetchFn: typeof fetch = fetch,
|
|
159
|
+
timeoutMs: number = PROVIDER_REQUEST_TIMEOUT_MS,
|
|
154
160
|
): Promise<Uint8Array> {
|
|
155
161
|
const choice = result.choices?.[0];
|
|
156
162
|
const message = choice?.message;
|
|
157
163
|
for (const image of message?.images ?? []) {
|
|
158
164
|
const imageUrl = extractImageUrl(image);
|
|
159
|
-
if (imageUrl !== null) return downloadImage(imageUrl, fetchFn);
|
|
165
|
+
if (imageUrl !== null) return downloadImage(imageUrl, fetchFn, timeoutMs);
|
|
160
166
|
}
|
|
161
167
|
if (Array.isArray(message?.content)) {
|
|
162
168
|
for (const item of message.content) {
|
|
@@ -211,6 +217,7 @@ export function buildRequestBody(
|
|
|
211
217
|
|
|
212
218
|
export const createOpenrouter: ProviderFactory = (options?: ProviderOptions): ImageProvider => {
|
|
213
219
|
const fetchFn = options?.fetch ?? fetch;
|
|
220
|
+
const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
|
|
214
221
|
const env = options?.env ?? process.env;
|
|
215
222
|
const readEnv = (key: string): string => env[key] ?? '';
|
|
216
223
|
|
|
@@ -246,11 +253,16 @@ export const createOpenrouter: ProviderFactory = (options?: ProviderOptions): Im
|
|
|
246
253
|
method: 'POST',
|
|
247
254
|
headers,
|
|
248
255
|
body: JSON.stringify(body),
|
|
256
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
249
257
|
});
|
|
250
258
|
if (!response.ok) {
|
|
251
259
|
throw new Error(`OpenRouter API error (${response.status}): ${await response.text()}`);
|
|
252
260
|
}
|
|
253
|
-
const bytes = await extractImageFromResponse(
|
|
261
|
+
const bytes = await extractImageFromResponse(
|
|
262
|
+
(await response.json()) as OpenRouterResponse,
|
|
263
|
+
fetchFn,
|
|
264
|
+
timeoutMs,
|
|
265
|
+
);
|
|
254
266
|
return { bytes, extension: 'png', provider: 'openrouter', model: req.model };
|
|
255
267
|
},
|
|
256
268
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { refToDataUri } from './refs';
|
|
2
2
|
import { extensionFromUrl } from './seedream';
|
|
3
|
+
import { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
3
4
|
import type { ImageProvider, ImageRequest, ImageResult, ProviderFactory, ProviderOptions } from './types';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -208,10 +209,11 @@ export function extractOutputUrl(prediction: PredictionResponse): string {
|
|
|
208
209
|
export const createReplicate: ProviderFactory = (options?: ProviderOptions): ImageProvider => {
|
|
209
210
|
const fetchFn = options?.fetch ?? fetch;
|
|
210
211
|
const env = options?.env ?? process.env;
|
|
212
|
+
const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
|
|
211
213
|
const readEnv = (key: string): string => env[key] ?? '';
|
|
212
214
|
|
|
213
215
|
async function downloadImage(url: string): Promise<Uint8Array> {
|
|
214
|
-
const res = await fetchFn(url);
|
|
216
|
+
const res = await fetchFn(url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
215
217
|
if (!res.ok) throw new Error(`Failed to download image from Replicate: ${res.status}`);
|
|
216
218
|
return new Uint8Array(await res.arrayBuffer());
|
|
217
219
|
}
|
|
@@ -219,7 +221,10 @@ export const createReplicate: ProviderFactory = (options?: ProviderOptions): Ima
|
|
|
219
221
|
async function pollPrediction(apiToken: string, getUrl: string): Promise<PredictionResponse> {
|
|
220
222
|
const start = Date.now();
|
|
221
223
|
while (Date.now() - start < MAX_POLL_MS) {
|
|
222
|
-
const res = await fetchFn(getUrl, {
|
|
224
|
+
const res = await fetchFn(getUrl, {
|
|
225
|
+
headers: { authorization: `Bearer ${apiToken}` },
|
|
226
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
227
|
+
});
|
|
223
228
|
if (!res.ok) throw new Error(`Replicate poll error (${res.status}): ${await res.text()}`);
|
|
224
229
|
const prediction = (await res.json()) as PredictionResponse;
|
|
225
230
|
if (prediction.status === 'succeeded') return prediction;
|
|
@@ -260,7 +265,12 @@ export const createReplicate: ProviderFactory = (options?: ProviderOptions): Ima
|
|
|
260
265
|
Prefer: `wait=${SYNC_WAIT_SECONDS}`,
|
|
261
266
|
};
|
|
262
267
|
let prediction = (await (
|
|
263
|
-
await fetchFn(url, {
|
|
268
|
+
await fetchFn(url, {
|
|
269
|
+
method: 'POST',
|
|
270
|
+
headers,
|
|
271
|
+
body: JSON.stringify(body),
|
|
272
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
273
|
+
})
|
|
264
274
|
).json()) as PredictionResponse;
|
|
265
275
|
if (prediction.status !== 'succeeded') {
|
|
266
276
|
if (prediction.urls?.get === undefined)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { readBytes } from '../bytes';
|
|
3
|
+
import { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
3
4
|
import type { ImageProvider, ImageRequest, ImageResult, ProviderFactory, ProviderOptions } from './types';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -36,6 +37,7 @@ export function extensionFromUrl(url: string): string {
|
|
|
36
37
|
|
|
37
38
|
export const createSeedream: ProviderFactory = (options?: ProviderOptions): ImageProvider => {
|
|
38
39
|
const fetchFn = options?.fetch ?? fetch;
|
|
40
|
+
const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
|
|
39
41
|
const env = options?.env ?? process.env;
|
|
40
42
|
const readEnv = (key: string): string => env[key] ?? '';
|
|
41
43
|
const supportsRef = (model: string): boolean => REF_MODEL_FRAGMENTS.some((fragment) => model.includes(fragment));
|
|
@@ -80,6 +82,7 @@ export const createSeedream: ProviderFactory = (options?: ProviderOptions): Imag
|
|
|
80
82
|
method: 'POST',
|
|
81
83
|
headers: { authorization: `Bearer ${apiKey}`, 'content-type': 'application/json' },
|
|
82
84
|
body: JSON.stringify(body),
|
|
85
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
83
86
|
});
|
|
84
87
|
const text = await resp.text();
|
|
85
88
|
if (!resp.ok) {
|
|
@@ -107,7 +110,7 @@ export const createSeedream: ProviderFactory = (options?: ProviderOptions): Imag
|
|
|
107
110
|
};
|
|
108
111
|
}
|
|
109
112
|
if (image.url !== undefined) {
|
|
110
|
-
const r = await fetchFn(image.url);
|
|
113
|
+
const r = await fetchFn(image.url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
111
114
|
if (!r.ok) {
|
|
112
115
|
throw new Error(`seedream fetch URL HTTP ${r.status}`);
|
|
113
116
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-request HTTP timeout shared by every image-gen provider.
|
|
3
|
+
*
|
|
4
|
+
* This lives in a leaf module (no imports) rather than in `types.ts` because `types.ts` builds the
|
|
5
|
+
* `PROVIDERS` registry from value imports of each adapter, which would make `types.ts ⇄ <adapter>`
|
|
6
|
+
* a runtime import cycle: a consumer that imported an adapter first (e.g. the google helper tests)
|
|
7
|
+
* would evaluate `types.ts` while the adapter was still initialising and hit a TDZ error on the
|
|
8
|
+
* registry's `create` reference. `types.ts` re-exports this constant, so importing it from there
|
|
9
|
+
* still works.
|
|
10
|
+
*
|
|
11
|
+
* Bun's `fetch` — like WHATWG fetch — has no overall request deadline unless a `signal` is passed,
|
|
12
|
+
* so a stalled peer would hang the workflow step until someone killed the run (R5).
|
|
13
|
+
*/
|
|
14
|
+
export const PROVIDER_REQUEST_TIMEOUT_MS = 300_000;
|
|
@@ -70,10 +70,20 @@ export interface ImageProvider {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/** Injection seam for tests — mirrors `VoiceboxClientOptions.fetch` (voice-gen). */
|
|
73
|
+
/**
|
|
74
|
+
* Default per-request timeout for every image-gen provider HTTP call. Defined in `./timeouts` (a
|
|
75
|
+
* leaf module) and re-exported here so `types.ts` stays the public surface; see that file for why
|
|
76
|
+
* it cannot be declared inline (import cycle → TDZ). Overridable per call via
|
|
77
|
+
* `ProviderOptions.timeoutMs` (tests).
|
|
78
|
+
*/
|
|
79
|
+
export { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
80
|
+
|
|
73
81
|
export interface ProviderOptions {
|
|
74
82
|
fetch?: typeof fetch;
|
|
75
83
|
/** Environment consulted instead of process.env (tests). */
|
|
76
84
|
env?: Record<string, string | undefined>;
|
|
85
|
+
/** Per-request timeout override (tests). Defaults to {@link PROVIDER_REQUEST_TIMEOUT_MS}. */
|
|
86
|
+
timeoutMs?: number;
|
|
77
87
|
}
|
|
78
88
|
|
|
79
89
|
export type ProviderFactory = (options?: ProviderOptions) => ImageProvider;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PROVIDER_REQUEST_TIMEOUT_MS } from './timeouts';
|
|
1
2
|
import type { ImageProvider, ImageRequest, ImageResult, ProviderFactory, ProviderOptions } from './types';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -180,6 +181,7 @@ interface ZaiResponse {
|
|
|
180
181
|
|
|
181
182
|
export const createZai: ProviderFactory = (options?: ProviderOptions): ImageProvider => {
|
|
182
183
|
const fetchFn = options?.fetch ?? fetch;
|
|
184
|
+
const timeoutMs = options?.timeoutMs ?? PROVIDER_REQUEST_TIMEOUT_MS;
|
|
183
185
|
const env = options?.env ?? process.env;
|
|
184
186
|
const readEnv = (key: string): string => env[key] ?? '';
|
|
185
187
|
|
|
@@ -220,11 +222,12 @@ export const createZai: ProviderFactory = (options?: ProviderOptions): ImageProv
|
|
|
220
222
|
quality: req.quality === 'normal' ? 'standard' : 'hd',
|
|
221
223
|
size,
|
|
222
224
|
}),
|
|
225
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
223
226
|
});
|
|
224
227
|
if (!response.ok) throw new Error(`Z.AI API error (${response.status}): ${await response.text()}`);
|
|
225
228
|
const url = ((await response.json()) as ZaiResponse).data?.[0]?.url;
|
|
226
229
|
if (url === undefined) throw new Error('No image URL in Z.AI response');
|
|
227
|
-
const imageResponse = await fetchFn(url);
|
|
230
|
+
const imageResponse = await fetchFn(url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
228
231
|
if (!imageResponse.ok) throw new Error(`Failed to download image from Z.AI: ${imageResponse.status}`);
|
|
229
232
|
return {
|
|
230
233
|
bytes: new Uint8Array(await imageResponse.arrayBuffer()),
|
|
@@ -21781,6 +21781,22 @@ var ResultSchema = exports_external.object({
|
|
|
21781
21781
|
error: exports_external.string().optional(),
|
|
21782
21782
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21783
21783
|
});
|
|
21784
|
+
var TargetOutcomeSchema = exports_external.object({
|
|
21785
|
+
target: exports_external.string(),
|
|
21786
|
+
ok: exports_external.boolean(),
|
|
21787
|
+
status: exports_external.enum(["published", "failed", "skipped"]),
|
|
21788
|
+
url: exports_external.string().optional(),
|
|
21789
|
+
id: exports_external.string().optional(),
|
|
21790
|
+
error: exports_external.string().optional(),
|
|
21791
|
+
durationMs: exports_external.number().optional(),
|
|
21792
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21793
|
+
});
|
|
21794
|
+
var AggregateResultSchema = exports_external.object({
|
|
21795
|
+
ok: exports_external.boolean(),
|
|
21796
|
+
summary: exports_external.object({ total: exports_external.number(), succeeded: exports_external.number(), failed: exports_external.number(), skipped: exports_external.number() }),
|
|
21797
|
+
targets: exports_external.array(TargetOutcomeSchema),
|
|
21798
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
21799
|
+
});
|
|
21784
21800
|
var DocListSchema = exports_external.array(DocSchema);
|
|
21785
21801
|
var omniVoiceGenContentSchema = ContentSchema.extend({
|
|
21786
21802
|
format: exports_external.literal("audio"),
|
|
@@ -21809,14 +21825,15 @@ var PluginKindSchema = exports_external.enum(PLUGIN_KINDS);
|
|
|
21809
21825
|
// ../../packages/kk-core/src/manifest.ts
|
|
21810
21826
|
init_zod();
|
|
21811
21827
|
var OperationIOSchema = exports_external.enum(["doc-list", "markdown"]);
|
|
21812
|
-
var
|
|
21828
|
+
var PluginOperationSchema = exports_external.object({ input: OperationIOSchema, output: OperationIOSchema });
|
|
21829
|
+
var PluginManifestSchema = exports_external.looseObject({
|
|
21813
21830
|
name: exports_external.string().min(1),
|
|
21814
21831
|
kind: PluginKindSchema,
|
|
21815
21832
|
entry: exports_external.string().min(1),
|
|
21816
21833
|
version: exports_external.string().optional(),
|
|
21817
21834
|
description: exports_external.string().optional(),
|
|
21818
|
-
operations: exports_external.record(exports_external.string(),
|
|
21819
|
-
})
|
|
21835
|
+
operations: exports_external.record(exports_external.string(), PluginOperationSchema).optional()
|
|
21836
|
+
});
|
|
21820
21837
|
// ../../node_modules/.bun/@gobing-ai+ts-runtime@0.4.39/node_modules/@gobing-ai/ts-runtime/dist/index.js
|
|
21821
21838
|
init_file_system_node();
|
|
21822
21839
|
init_config();
|