@cf-vibesdk/sdk 0.0.2 → 0.0.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/README.md +1 -1
- package/dist/index.js +265 -45
- package/package.json +1 -3
- package/dist/index.d.ts +0 -1737
- package/dist/node.d.ts +0 -77
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// src/retry.ts
|
|
3
|
+
function normalizeRetryConfig(retry, defaults) {
|
|
4
|
+
return {
|
|
5
|
+
enabled: retry?.enabled ?? defaults.enabled,
|
|
6
|
+
initialDelayMs: retry?.initialDelayMs ?? defaults.initialDelayMs,
|
|
7
|
+
maxDelayMs: retry?.maxDelayMs ?? defaults.maxDelayMs,
|
|
8
|
+
maxRetries: retry?.maxRetries ?? defaults.maxRetries
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function computeBackoffMs(attempt, cfg) {
|
|
12
|
+
const base = Math.min(cfg.maxDelayMs, cfg.initialDelayMs * Math.pow(2, Math.max(0, attempt)));
|
|
13
|
+
const jitter = base * 0.2;
|
|
14
|
+
return Math.max(0, Math.floor(base - jitter + Math.random() * jitter * 2));
|
|
15
|
+
}
|
|
16
|
+
function sleep(ms) {
|
|
17
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
18
|
+
}
|
|
19
|
+
|
|
2
20
|
// src/http.ts
|
|
21
|
+
var HTTP_RETRY_DEFAULTS = {
|
|
22
|
+
enabled: true,
|
|
23
|
+
initialDelayMs: 1000,
|
|
24
|
+
maxDelayMs: 1e4,
|
|
25
|
+
maxRetries: 3
|
|
26
|
+
};
|
|
27
|
+
function isRetryableStatus(status) {
|
|
28
|
+
return status >= 500 && status < 600;
|
|
29
|
+
}
|
|
30
|
+
|
|
3
31
|
class HttpClient {
|
|
4
32
|
opts;
|
|
5
33
|
cachedAccessToken = null;
|
|
34
|
+
retryCfg;
|
|
6
35
|
constructor(opts) {
|
|
7
36
|
this.opts = opts;
|
|
37
|
+
this.retryCfg = normalizeRetryConfig(opts.retry, HTTP_RETRY_DEFAULTS);
|
|
8
38
|
}
|
|
9
39
|
get baseUrl() {
|
|
10
40
|
return this.opts.baseUrl.replace(/\/$/, "");
|
|
@@ -34,7 +64,7 @@ class HttpClient {
|
|
|
34
64
|
}
|
|
35
65
|
});
|
|
36
66
|
if (!resp.ok) {
|
|
37
|
-
const text = await resp.text().catch(() => "");
|
|
67
|
+
const text = (await resp.text().catch(() => "")).slice(0, 1000);
|
|
38
68
|
if (resp.status === 401) {
|
|
39
69
|
throw new Error(`HTTP 401 for /api/auth/exchange-api-key: invalid API key (regenerate in Settings \u2192 API Keys). ${text || ""}`.trim());
|
|
40
70
|
}
|
|
@@ -60,21 +90,59 @@ class HttpClient {
|
|
|
60
90
|
}
|
|
61
91
|
async fetchJson(path, init) {
|
|
62
92
|
const url = `${this.baseUrl}${path}`;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
93
|
+
let lastError = null;
|
|
94
|
+
for (let attempt = 0;attempt <= this.retryCfg.maxRetries; attempt++) {
|
|
95
|
+
try {
|
|
96
|
+
const resp = await this.fetchFn(url, init);
|
|
97
|
+
if (!resp.ok) {
|
|
98
|
+
const text = (await resp.text().catch(() => "")).slice(0, 1000);
|
|
99
|
+
const error = new Error(`HTTP ${resp.status} for ${path}: ${text || resp.statusText}`);
|
|
100
|
+
if (this.retryCfg.enabled && isRetryableStatus(resp.status) && attempt < this.retryCfg.maxRetries) {
|
|
101
|
+
lastError = error;
|
|
102
|
+
await sleep(computeBackoffMs(attempt, this.retryCfg));
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
return await resp.json();
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (error instanceof TypeError && this.retryCfg.enabled && attempt < this.retryCfg.maxRetries) {
|
|
110
|
+
lastError = error;
|
|
111
|
+
await sleep(computeBackoffMs(attempt, this.retryCfg));
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
67
116
|
}
|
|
68
|
-
|
|
117
|
+
throw lastError ?? new Error(`Failed after ${this.retryCfg.maxRetries} retries`);
|
|
69
118
|
}
|
|
70
119
|
async fetchRaw(path, init) {
|
|
71
120
|
const url = `${this.baseUrl}${path}`;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
121
|
+
let lastError = null;
|
|
122
|
+
for (let attempt = 0;attempt <= this.retryCfg.maxRetries; attempt++) {
|
|
123
|
+
try {
|
|
124
|
+
const resp = await this.fetchFn(url, init);
|
|
125
|
+
if (!resp.ok) {
|
|
126
|
+
const text = (await resp.text().catch(() => "")).slice(0, 1000);
|
|
127
|
+
const error = new Error(`HTTP ${resp.status} for ${path}: ${text || resp.statusText}`);
|
|
128
|
+
if (this.retryCfg.enabled && isRetryableStatus(resp.status) && attempt < this.retryCfg.maxRetries) {
|
|
129
|
+
lastError = error;
|
|
130
|
+
await sleep(computeBackoffMs(attempt, this.retryCfg));
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
return resp;
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (error instanceof TypeError && this.retryCfg.enabled && attempt < this.retryCfg.maxRetries) {
|
|
138
|
+
lastError = error;
|
|
139
|
+
await sleep(computeBackoffMs(attempt, this.retryCfg));
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
76
144
|
}
|
|
77
|
-
|
|
145
|
+
throw lastError ?? new Error(`Failed after ${this.retryCfg.maxRetries} retries`);
|
|
78
146
|
}
|
|
79
147
|
}
|
|
80
148
|
|
|
@@ -137,19 +205,25 @@ class TypedEmitter {
|
|
|
137
205
|
for (const cb of set)
|
|
138
206
|
cb(payload);
|
|
139
207
|
}
|
|
208
|
+
clear() {
|
|
209
|
+
this.listeners.clear();
|
|
210
|
+
this.anyListeners.clear();
|
|
211
|
+
}
|
|
140
212
|
}
|
|
141
213
|
|
|
142
214
|
// src/state.ts
|
|
143
215
|
var INITIAL_STATE = {
|
|
216
|
+
connection: "disconnected",
|
|
144
217
|
generation: { status: "idle" },
|
|
145
218
|
phase: { status: "idle" },
|
|
146
219
|
preview: { status: "idle" },
|
|
147
220
|
cloudflare: { status: "idle" }
|
|
148
221
|
};
|
|
149
222
|
function extractPhaseInfo(msg) {
|
|
223
|
+
const phase = msg?.phase;
|
|
150
224
|
return {
|
|
151
|
-
name:
|
|
152
|
-
description:
|
|
225
|
+
name: phase?.name,
|
|
226
|
+
description: phase?.description
|
|
153
227
|
};
|
|
154
228
|
}
|
|
155
229
|
|
|
@@ -162,6 +236,9 @@ class SessionStateStore {
|
|
|
162
236
|
onChange(cb) {
|
|
163
237
|
return this.emitter.on("change", ({ prev, next }) => cb(next, prev));
|
|
164
238
|
}
|
|
239
|
+
setConnection(state) {
|
|
240
|
+
this.setState({ connection: state });
|
|
241
|
+
}
|
|
165
242
|
applyWsMessage(msg) {
|
|
166
243
|
switch (msg.type) {
|
|
167
244
|
case "conversation_state": {
|
|
@@ -176,29 +253,57 @@ class SessionStateStore {
|
|
|
176
253
|
}
|
|
177
254
|
case "generation_started": {
|
|
178
255
|
const m = msg;
|
|
179
|
-
this.setState({
|
|
256
|
+
this.setState({
|
|
257
|
+
generation: { status: "running", totalFiles: m.totalFiles, filesGenerated: 0 },
|
|
258
|
+
currentFile: undefined
|
|
259
|
+
});
|
|
180
260
|
break;
|
|
181
261
|
}
|
|
182
262
|
case "generation_complete": {
|
|
183
263
|
const m = msg;
|
|
184
264
|
const previewURL = m.previewURL;
|
|
265
|
+
const prev = this.state.generation;
|
|
266
|
+
const filesGenerated = "filesGenerated" in prev ? prev.filesGenerated : 0;
|
|
185
267
|
this.setState({
|
|
186
268
|
generation: {
|
|
187
269
|
status: "complete",
|
|
188
270
|
instanceId: m.instanceId,
|
|
189
|
-
previewURL
|
|
271
|
+
previewURL,
|
|
272
|
+
filesGenerated
|
|
190
273
|
},
|
|
274
|
+
currentFile: undefined,
|
|
191
275
|
...previewURL ? { previewUrl: previewURL } : {}
|
|
192
276
|
});
|
|
193
277
|
break;
|
|
194
278
|
}
|
|
195
279
|
case "generation_stopped": {
|
|
196
280
|
const m = msg;
|
|
197
|
-
|
|
281
|
+
const prev = this.state.generation;
|
|
282
|
+
const filesGenerated = "filesGenerated" in prev ? prev.filesGenerated : 0;
|
|
283
|
+
this.setState({
|
|
284
|
+
generation: { status: "stopped", instanceId: m.instanceId, filesGenerated }
|
|
285
|
+
});
|
|
198
286
|
break;
|
|
199
287
|
}
|
|
200
288
|
case "generation_resumed": {
|
|
201
|
-
this.
|
|
289
|
+
const prev = this.state.generation;
|
|
290
|
+
const filesGenerated = "filesGenerated" in prev ? prev.filesGenerated : 0;
|
|
291
|
+
this.setState({ generation: { status: "running", filesGenerated } });
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
case "file_generating": {
|
|
295
|
+
const m = msg;
|
|
296
|
+
this.setState({ currentFile: m.filePath });
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
case "file_generated": {
|
|
300
|
+
const prev = this.state.generation;
|
|
301
|
+
if (prev.status === "running" || prev.status === "stopped") {
|
|
302
|
+
this.setState({
|
|
303
|
+
generation: { ...prev, filesGenerated: prev.filesGenerated + 1 },
|
|
304
|
+
currentFile: undefined
|
|
305
|
+
});
|
|
306
|
+
}
|
|
202
307
|
break;
|
|
203
308
|
}
|
|
204
309
|
case "phase_generating": {
|
|
@@ -299,6 +404,10 @@ class SessionStateStore {
|
|
|
299
404
|
this.state = next;
|
|
300
405
|
this.emitter.emit("change", { prev, next });
|
|
301
406
|
}
|
|
407
|
+
clear() {
|
|
408
|
+
this.state = INITIAL_STATE;
|
|
409
|
+
this.emitter.clear();
|
|
410
|
+
}
|
|
302
411
|
}
|
|
303
412
|
|
|
304
413
|
// src/ws.ts
|
|
@@ -308,23 +417,15 @@ function toWsCloseEvent(ev) {
|
|
|
308
417
|
reason: typeof ev.reason === "string" ? ev.reason : ""
|
|
309
418
|
};
|
|
310
419
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
maxRetries: retry?.maxRetries ?? Infinity
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
function computeBackoffMs(attempt, cfg) {
|
|
321
|
-
const base = Math.min(cfg.maxDelayMs, cfg.initialDelayMs * Math.pow(2, Math.max(0, attempt)));
|
|
322
|
-
const jitter = base * 0.2;
|
|
323
|
-
return Math.max(0, Math.floor(base - jitter + Math.random() * jitter * 2));
|
|
324
|
-
}
|
|
420
|
+
var WS_RETRY_DEFAULTS = {
|
|
421
|
+
enabled: true,
|
|
422
|
+
initialDelayMs: 1000,
|
|
423
|
+
maxDelayMs: 30000,
|
|
424
|
+
maxRetries: Infinity
|
|
425
|
+
};
|
|
325
426
|
function createAgentConnection(url, options = {}) {
|
|
326
427
|
const emitter = new TypedEmitter;
|
|
327
|
-
const retryCfg = normalizeRetryConfig(options.retry);
|
|
428
|
+
const retryCfg = normalizeRetryConfig(options.retry, WS_RETRY_DEFAULTS);
|
|
328
429
|
const headers = { ...options.headers ?? {} };
|
|
329
430
|
if (options.origin)
|
|
330
431
|
headers.Origin = options.origin;
|
|
@@ -501,7 +602,7 @@ function createAgentConnection(url, options = {}) {
|
|
|
501
602
|
}
|
|
502
603
|
if (ws.on) {
|
|
503
604
|
ws.on("open", () => onOpen());
|
|
504
|
-
ws.on("close", (code, reason) => onClose({ code, reason }));
|
|
605
|
+
ws.on("close", (code, reason) => onClose({ code: typeof code === "number" ? code : undefined, reason: typeof reason === "string" ? reason : undefined }));
|
|
505
606
|
ws.on("error", (error) => onError(error));
|
|
506
607
|
ws.on("message", (data) => onMessage(data));
|
|
507
608
|
}
|
|
@@ -514,8 +615,12 @@ function createAgentConnection(url, options = {}) {
|
|
|
514
615
|
return;
|
|
515
616
|
}
|
|
516
617
|
pendingSends.push(data);
|
|
517
|
-
if (pendingSends.length > maxPendingSends)
|
|
618
|
+
if (pendingSends.length > maxPendingSends) {
|
|
518
619
|
pendingSends.shift();
|
|
620
|
+
emitter.emit("ws:error", {
|
|
621
|
+
error: new Error(`Message queue overflow: dropped oldest message (queue size: ${maxPendingSends})`)
|
|
622
|
+
});
|
|
623
|
+
}
|
|
519
624
|
}
|
|
520
625
|
function close() {
|
|
521
626
|
closedByUser = true;
|
|
@@ -553,25 +658,24 @@ function createAgentConnection(url, options = {}) {
|
|
|
553
658
|
function isRecord(value) {
|
|
554
659
|
return typeof value === "object" && value !== null;
|
|
555
660
|
}
|
|
661
|
+
function isFileOutputType(value) {
|
|
662
|
+
if (!isRecord(value))
|
|
663
|
+
return false;
|
|
664
|
+
return typeof value.filePath === "string" && typeof value.fileContents === "string";
|
|
665
|
+
}
|
|
556
666
|
function extractGeneratedFilesFromState(state) {
|
|
557
667
|
const out = [];
|
|
558
668
|
for (const file of Object.values(state.generatedFilesMap ?? {})) {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
out.push({ path, content });
|
|
563
|
-
}
|
|
669
|
+
if (!isFileOutputType(file))
|
|
670
|
+
continue;
|
|
671
|
+
out.push({ path: file.filePath, content: file.fileContents });
|
|
564
672
|
}
|
|
565
673
|
return out;
|
|
566
674
|
}
|
|
567
675
|
function extractGeneratedFileFromMessageFile(file) {
|
|
568
|
-
if (!
|
|
676
|
+
if (!isFileOutputType(file))
|
|
569
677
|
return null;
|
|
570
|
-
|
|
571
|
-
const content = file.fileContents;
|
|
572
|
-
if (typeof path !== "string" || typeof content !== "string")
|
|
573
|
-
return null;
|
|
574
|
-
return { path, content };
|
|
678
|
+
return { path: file.filePath, content: file.fileContents };
|
|
575
679
|
}
|
|
576
680
|
|
|
577
681
|
class WorkspaceStore {
|
|
@@ -624,6 +728,10 @@ class WorkspaceStore {
|
|
|
624
728
|
break;
|
|
625
729
|
}
|
|
626
730
|
}
|
|
731
|
+
clear() {
|
|
732
|
+
this.files.clear();
|
|
733
|
+
this.emitter.clear();
|
|
734
|
+
}
|
|
627
735
|
}
|
|
628
736
|
|
|
629
737
|
// src/session.ts
|
|
@@ -713,11 +821,18 @@ class BuildSession {
|
|
|
713
821
|
...Object.keys(headers).length ? { headers } : {},
|
|
714
822
|
...webSocketFactory ? { webSocketFactory } : {}
|
|
715
823
|
};
|
|
824
|
+
this.state.setConnection("connecting");
|
|
716
825
|
this.connection = createAgentConnection(this.websocketUrl, connectOptions);
|
|
717
826
|
this.connection.on("ws:message", (m) => {
|
|
718
827
|
this.workspace.applyWsMessage(m);
|
|
719
828
|
this.state.applyWsMessage(m);
|
|
720
829
|
});
|
|
830
|
+
this.connection.on("ws:open", () => {
|
|
831
|
+
this.state.setConnection("connected");
|
|
832
|
+
});
|
|
833
|
+
this.connection.on("ws:close", () => {
|
|
834
|
+
this.state.setConnection("disconnected");
|
|
835
|
+
});
|
|
721
836
|
const credentials = agentOptions.credentials ?? this.init.defaultCredentials;
|
|
722
837
|
const shouldRequestConversationState = autoRequestConversationState ?? true;
|
|
723
838
|
this.connection.on("ws:open", () => {
|
|
@@ -843,6 +958,8 @@ class BuildSession {
|
|
|
843
958
|
close() {
|
|
844
959
|
this.connection?.close();
|
|
845
960
|
this.connection = null;
|
|
961
|
+
this.workspace.clear();
|
|
962
|
+
this.state.clear();
|
|
846
963
|
}
|
|
847
964
|
assertConnected() {
|
|
848
965
|
if (!this.connection) {
|
|
@@ -983,11 +1100,114 @@ class PhasicClient extends VibeClient {
|
|
|
983
1100
|
return super.build(prompt, { ...options, behaviorType: options.behaviorType ?? "phasic" });
|
|
984
1101
|
}
|
|
985
1102
|
}
|
|
1103
|
+
// src/blueprint.ts
|
|
1104
|
+
function isRecord2(v) {
|
|
1105
|
+
return Boolean(v) && typeof v === "object" && !Array.isArray(v);
|
|
1106
|
+
}
|
|
1107
|
+
function blueprintToMarkdown(bp) {
|
|
1108
|
+
const lines = [];
|
|
1109
|
+
const title = bp.title ?? bp.projectName ?? "Blueprint";
|
|
1110
|
+
lines.push(`# ${title}`);
|
|
1111
|
+
if (bp.description) {
|
|
1112
|
+
lines.push("");
|
|
1113
|
+
lines.push(bp.description);
|
|
1114
|
+
}
|
|
1115
|
+
if (bp.frameworks?.length) {
|
|
1116
|
+
lines.push("");
|
|
1117
|
+
lines.push("## Frameworks");
|
|
1118
|
+
for (const f of bp.frameworks)
|
|
1119
|
+
lines.push(`- ${f}`);
|
|
1120
|
+
}
|
|
1121
|
+
if (bp.detailedDescription) {
|
|
1122
|
+
lines.push("");
|
|
1123
|
+
lines.push("## Details");
|
|
1124
|
+
lines.push(bp.detailedDescription);
|
|
1125
|
+
}
|
|
1126
|
+
if (bp.views?.length) {
|
|
1127
|
+
lines.push("");
|
|
1128
|
+
lines.push("## Views");
|
|
1129
|
+
for (const v of bp.views)
|
|
1130
|
+
lines.push(`- **${v.name}**: ${v.description}`);
|
|
1131
|
+
}
|
|
1132
|
+
if (bp.plan?.length) {
|
|
1133
|
+
lines.push("");
|
|
1134
|
+
lines.push("## Plan");
|
|
1135
|
+
bp.plan.forEach((s, idx) => lines.push(`${idx + 1}. ${s}`));
|
|
1136
|
+
}
|
|
1137
|
+
if (bp.implementationRoadmap?.length) {
|
|
1138
|
+
lines.push("");
|
|
1139
|
+
lines.push("## Roadmap");
|
|
1140
|
+
for (const p of bp.implementationRoadmap)
|
|
1141
|
+
lines.push(`- **${p.phase}**: ${p.description}`);
|
|
1142
|
+
}
|
|
1143
|
+
return lines.join(`
|
|
1144
|
+
`);
|
|
1145
|
+
}
|
|
1146
|
+
function extractJsonStringField(raw, key) {
|
|
1147
|
+
const re = new RegExp(`"${key}"\\s*:\\s*"([^"\\n\\r]*)"`);
|
|
1148
|
+
const m = re.exec(raw);
|
|
1149
|
+
return m?.[1] ?? null;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
class BlueprintStreamParser {
|
|
1153
|
+
buffer = "";
|
|
1154
|
+
append(chunk) {
|
|
1155
|
+
this.buffer += chunk;
|
|
1156
|
+
return this.toMarkdown();
|
|
1157
|
+
}
|
|
1158
|
+
toMarkdown() {
|
|
1159
|
+
const startsLikeJson = /^\s*[\[{]/.test(this.buffer);
|
|
1160
|
+
if (!startsLikeJson) {
|
|
1161
|
+
return this.buffer;
|
|
1162
|
+
}
|
|
1163
|
+
try {
|
|
1164
|
+
const parsed = JSON.parse(this.buffer);
|
|
1165
|
+
if (isRecord2(parsed)) {
|
|
1166
|
+
return blueprintToMarkdown(parsed);
|
|
1167
|
+
}
|
|
1168
|
+
} catch {}
|
|
1169
|
+
const title = extractJsonStringField(this.buffer, "title") ?? extractJsonStringField(this.buffer, "projectName") ?? "Blueprint";
|
|
1170
|
+
const desc = extractJsonStringField(this.buffer, "description");
|
|
1171
|
+
const lines = [`# ${title}`, "", desc ? desc : "*Generating blueprint...*"];
|
|
1172
|
+
return lines.join(`
|
|
1173
|
+
`);
|
|
1174
|
+
}
|
|
1175
|
+
getRaw() {
|
|
1176
|
+
return this.buffer;
|
|
1177
|
+
}
|
|
1178
|
+
clear() {
|
|
1179
|
+
this.buffer = "";
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
// src/utils.ts
|
|
1183
|
+
class TimeoutError extends Error {
|
|
1184
|
+
constructor(message) {
|
|
1185
|
+
super(message);
|
|
1186
|
+
this.name = "TimeoutError";
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
async function withTimeout(promise, ms, message = "Operation timed out") {
|
|
1190
|
+
let timeoutId;
|
|
1191
|
+
const timeout = new Promise((_, reject) => {
|
|
1192
|
+
timeoutId = setTimeout(() => reject(new TimeoutError(message)), ms);
|
|
1193
|
+
});
|
|
1194
|
+
try {
|
|
1195
|
+
return await Promise.race([promise, timeout]);
|
|
1196
|
+
} finally {
|
|
1197
|
+
if (timeoutId !== undefined)
|
|
1198
|
+
clearTimeout(timeoutId);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
986
1201
|
export {
|
|
1202
|
+
withTimeout,
|
|
1203
|
+
isRecord2 as isRecord,
|
|
1204
|
+
blueprintToMarkdown,
|
|
987
1205
|
WorkspaceStore,
|
|
988
1206
|
VibeClient,
|
|
1207
|
+
TimeoutError,
|
|
989
1208
|
SessionStateStore,
|
|
990
1209
|
PhasicClient,
|
|
991
1210
|
BuildSession,
|
|
1211
|
+
BlueprintStreamParser,
|
|
992
1212
|
AgenticClient
|
|
993
1213
|
};
|