@dmrlzz/davecode 0.5.0 → 0.5.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/dist/{ChatApp-CJBICQGA.js → ChatApp-Z6PQIZ5J.js} +7 -6
- package/dist/{ChatApp-CJBICQGA.js.map → ChatApp-Z6PQIZ5J.js.map} +1 -1
- package/dist/{account-QWDPJWAA.js → account-RTPS2V6O.js} +4 -3
- package/dist/{accounts-IQMR72FC.js → accounts-IYQ4ZRL7.js} +6 -5
- package/dist/{budget-XANOUVWO.js → budget-N2ZB66FF.js} +5 -4
- package/dist/{budget-XANOUVWO.js.map → budget-N2ZB66FF.js.map} +1 -1
- package/dist/{chat-KDDRNC5V.js → chat-6TX6JX45.js} +9 -8
- package/dist/{chat-KDDRNC5V.js.map → chat-6TX6JX45.js.map} +1 -1
- package/dist/chunk-732GIHRQ.js +23 -0
- package/dist/chunk-732GIHRQ.js.map +1 -0
- package/dist/{chunk-AZKACMME.js → chunk-BJTXMET2.js} +2 -2
- package/dist/{chunk-FYPMA55O.js → chunk-KUY3QHGS.js} +239 -106
- package/dist/chunk-KUY3QHGS.js.map +1 -0
- package/dist/{chunk-JLATEHS7.js → chunk-LEU46DGH.js} +2 -2
- package/dist/{chunk-HSBJDV3O.js → chunk-QKY3OKVG.js} +309 -23
- package/dist/chunk-QKY3OKVG.js.map +1 -0
- package/dist/{chunk-WQ7MEWDF.js → chunk-UEV5K3DH.js} +10 -4
- package/dist/chunk-UEV5K3DH.js.map +1 -0
- package/dist/{chunk-44AFJL2X.js → chunk-UNK3EQD6.js} +6 -5
- package/dist/chunk-UNK3EQD6.js.map +1 -0
- package/dist/{chunk-W7GPBEBZ.js → chunk-WAARDGCZ.js} +5 -21
- package/dist/chunk-WAARDGCZ.js.map +1 -0
- package/dist/{chunk-PGAJIGUF.js → chunk-YNAMNQLW.js} +3 -3
- package/dist/{config-YTUPIYZT.js → config-YQKY2AA4.js} +4 -3
- package/dist/{config-YTUPIYZT.js.map → config-YQKY2AA4.js.map} +1 -1
- package/dist/dashboard/assets/Accounts-DXiGsutB.js +1 -0
- package/dist/dashboard/assets/{Badge-Z4RBdO9j.js → Badge-DUGKlx3Z.js} +1 -1
- package/dist/dashboard/assets/{Callout-w8BTYh4k.js → Callout-1E8Wsl9W.js} +1 -1
- package/dist/dashboard/assets/{Goals-Bw02to72.js → Goals-kL4VAxw3.js} +1 -1
- package/dist/dashboard/assets/{Library-DK7mlpRb.js → Library-DZxBVUo_.js} +1 -1
- package/dist/dashboard/assets/Markdown-CGgIydUh.js +71 -0
- package/dist/dashboard/assets/{Panes-_KTf8pbZ.js → Panes-C-TJekjs.js} +1 -1
- package/dist/dashboard/assets/{RoutesPage-QV0oPRW9.js → RoutesPage-DWYm9tW8.js} +1 -1
- package/dist/dashboard/assets/{Runner-CkHBLQl0.js → Runner-CmHBjECR.js} +1 -1
- package/dist/dashboard/assets/{Settings-BLz2gTBR.js → Settings-BANphxva.js} +1 -1
- package/dist/dashboard/assets/{Tasks-BiUQSTpt.js → Tasks-cSx1PKyQ.js} +1 -1
- package/dist/dashboard/assets/{Traffic-BVfBuC70.js → Traffic-DEAuM6jq.js} +1 -1
- package/dist/dashboard/assets/{Workspace-CJTgiiU5.js → Workspace-BQFjc1jH.js} +1 -1
- package/dist/dashboard/assets/index-B8kld9xo.js +104 -0
- package/dist/dashboard/assets/{task-errors-Daqwi0ue.js → task-errors-r-WYZ_S3.js} +1 -1
- package/dist/dashboard/index.html +2 -2
- package/dist/{dist-37VQSHHA.js → dist-PIC255RX.js} +20 -2
- package/dist/{doctor-PYUQRRCB.js → doctor-PQC7JQPP.js} +4 -3
- package/dist/{doctor-PYUQRRCB.js.map → doctor-PQC7JQPP.js.map} +1 -1
- package/dist/{goal-SXZUDUCL.js → goal-STLEU7C7.js} +4 -3
- package/dist/{goal-SXZUDUCL.js.map → goal-STLEU7C7.js.map} +1 -1
- package/dist/index.js +31 -31
- package/dist/{init-Z2AFQEEP.js → init-NHU5LJSS.js} +4 -3
- package/dist/{init-Z2AFQEEP.js.map → init-NHU5LJSS.js.map} +1 -1
- package/dist/{run-AOS7L3RT.js → run-7HWSHMRJ.js} +4 -3
- package/dist/{run-AOS7L3RT.js.map → run-7HWSHMRJ.js.map} +1 -1
- package/dist/runtime.js +3 -2
- package/dist/{start-CEPXKZUE.js → start-WVAEAQWL.js} +4 -3
- package/dist/{start-CEPXKZUE.js.map → start-WVAEAQWL.js.map} +1 -1
- package/dist/{status-WNJ3GGKU.js → status-ZRHPFLFT.js} +5 -4
- package/dist/{tasks-TFUTUMWB.js → tasks-JVWXUNXN.js} +5 -4
- package/dist/{tasks-TFUTUMWB.js.map → tasks-JVWXUNXN.js.map} +1 -1
- package/package.json +6 -6
- package/dist/chunk-44AFJL2X.js.map +0 -1
- package/dist/chunk-FYPMA55O.js.map +0 -1
- package/dist/chunk-HSBJDV3O.js.map +0 -1
- package/dist/chunk-W7GPBEBZ.js.map +0 -1
- package/dist/chunk-WQ7MEWDF.js.map +0 -1
- package/dist/dashboard/assets/Accounts-cq8RLMoI.js +0 -1
- package/dist/dashboard/assets/Markdown-DCZ4Awcc.js +0 -69
- package/dist/dashboard/assets/index-BDBa5cb0.js +0 -104
- /package/dist/{account-QWDPJWAA.js.map → account-RTPS2V6O.js.map} +0 -0
- /package/dist/{accounts-IQMR72FC.js.map → accounts-IYQ4ZRL7.js.map} +0 -0
- /package/dist/{chunk-AZKACMME.js.map → chunk-BJTXMET2.js.map} +0 -0
- /package/dist/{chunk-JLATEHS7.js.map → chunk-LEU46DGH.js.map} +0 -0
- /package/dist/{chunk-PGAJIGUF.js.map → chunk-YNAMNQLW.js.map} +0 -0
- /package/dist/{dist-37VQSHHA.js.map → dist-PIC255RX.js.map} +0 -0
- /package/dist/{status-WNJ3GGKU.js.map → status-ZRHPFLFT.js.map} +0 -0
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
openBrowser
|
|
3
|
+
} from "./chunk-732GIHRQ.js";
|
|
1
4
|
import {
|
|
2
5
|
ConfigError,
|
|
3
6
|
PROVIDER_KINDS,
|
|
@@ -9,16 +12,20 @@ import {
|
|
|
9
12
|
TaskGraphError,
|
|
10
13
|
VERSION,
|
|
11
14
|
WorkspaceLock,
|
|
15
|
+
apiConfigIssues,
|
|
12
16
|
connectionMethod,
|
|
17
|
+
createAccountControl,
|
|
13
18
|
createEngine,
|
|
14
19
|
createGoalService,
|
|
15
20
|
createRunner,
|
|
21
|
+
endpointRebindIssue,
|
|
16
22
|
loginCommandFor,
|
|
17
23
|
loginFromEnv,
|
|
24
|
+
mergeApiConfig,
|
|
18
25
|
newId2,
|
|
19
26
|
routeSchema,
|
|
20
27
|
taskIdSchema
|
|
21
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-QKY3OKVG.js";
|
|
22
29
|
|
|
23
30
|
// src/runtime.ts
|
|
24
31
|
import { existsSync as existsSync3 } from "fs";
|
|
@@ -34,13 +41,14 @@ import { resolve } from "path";
|
|
|
34
41
|
import cors from "@fastify/cors";
|
|
35
42
|
import fastifyStatic from "@fastify/static";
|
|
36
43
|
import Fastify from "fastify";
|
|
37
|
-
import { z as z4 } from "zod";
|
|
38
44
|
import { z } from "zod";
|
|
45
|
+
import { z as z5 } from "zod";
|
|
39
46
|
import { z as z2 } from "zod";
|
|
40
47
|
import { z as z3 } from "zod";
|
|
41
|
-
import { z as
|
|
42
|
-
import { Readable } from "stream";
|
|
48
|
+
import { z as z4 } from "zod";
|
|
43
49
|
import { z as z6 } from "zod";
|
|
50
|
+
import { Readable } from "stream";
|
|
51
|
+
import { z as z7 } from "zod";
|
|
44
52
|
function sendApiError(reply, status, code, message, extra = {}) {
|
|
45
53
|
return reply.code(status).send({ error: { message, code, ...extra } });
|
|
46
54
|
}
|
|
@@ -89,55 +97,81 @@ function describeRoutingError(err) {
|
|
|
89
97
|
body: { message: "Internal gateway error", type: "api_error", code: "internal_error" }
|
|
90
98
|
};
|
|
91
99
|
}
|
|
92
|
-
var
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
var loginSchema = z.object({ provider: z.enum(["google", "github"]).optional() });
|
|
101
|
+
function registerAccountRoutes(app, account) {
|
|
102
|
+
if (!account) return;
|
|
103
|
+
app.get("/api/account", async (_request, reply) => {
|
|
104
|
+
reply.header("Cache-Control", "no-store");
|
|
105
|
+
return account.state();
|
|
106
|
+
});
|
|
107
|
+
app.post("/api/account/login", async (request, reply) => {
|
|
108
|
+
const parsed = loginSchema.safeParse(request.body ?? {});
|
|
109
|
+
if (!parsed.success)
|
|
110
|
+
return sendApiError(reply, 400, "invalid_body", "Unknown sign-in provider.");
|
|
111
|
+
try {
|
|
112
|
+
return reply.code(202).send(await account.login(parsed.data.provider));
|
|
113
|
+
} catch {
|
|
114
|
+
return sendApiError(reply, 502, "account_unavailable", "Could not start the sign-in.");
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
app.post("/api/account/cancel", async (_request, reply) => {
|
|
118
|
+
await account.cancel();
|
|
119
|
+
return reply.code(204).send();
|
|
120
|
+
});
|
|
121
|
+
app.post("/api/account/logout", async (_request, reply) => {
|
|
122
|
+
await account.logout();
|
|
123
|
+
return reply.code(204).send();
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
var providerKind = z2.enum(PROVIDER_KINDS);
|
|
127
|
+
var contentPart = z2.discriminatedUnion("type", [
|
|
128
|
+
z2.object({ type: z2.literal("text"), text: z2.string() }),
|
|
129
|
+
z2.object({
|
|
130
|
+
type: z2.literal("image_url"),
|
|
131
|
+
image_url: z2.object({
|
|
132
|
+
url: z2.string(),
|
|
133
|
+
detail: z2.enum(["auto", "low", "high"]).optional()
|
|
100
134
|
})
|
|
101
135
|
})
|
|
102
136
|
]);
|
|
103
|
-
var toolCall =
|
|
104
|
-
id:
|
|
105
|
-
type:
|
|
106
|
-
function:
|
|
137
|
+
var toolCall = z2.object({
|
|
138
|
+
id: z2.string(),
|
|
139
|
+
type: z2.literal("function"),
|
|
140
|
+
function: z2.object({ name: z2.string(), arguments: z2.string() })
|
|
107
141
|
});
|
|
108
|
-
var chatMessage =
|
|
109
|
-
role:
|
|
110
|
-
content:
|
|
111
|
-
name:
|
|
112
|
-
tool_call_id:
|
|
113
|
-
tool_calls:
|
|
142
|
+
var chatMessage = z2.object({
|
|
143
|
+
role: z2.enum(["system", "user", "assistant", "tool"]),
|
|
144
|
+
content: z2.union([z2.string(), z2.array(contentPart), z2.null()]),
|
|
145
|
+
name: z2.string().optional(),
|
|
146
|
+
tool_call_id: z2.string().optional(),
|
|
147
|
+
tool_calls: z2.array(toolCall).optional()
|
|
114
148
|
});
|
|
115
|
-
var chatRequestSchema =
|
|
116
|
-
model:
|
|
117
|
-
messages:
|
|
118
|
-
stream:
|
|
119
|
-
temperature:
|
|
120
|
-
top_p:
|
|
121
|
-
max_tokens:
|
|
122
|
-
stop:
|
|
123
|
-
tools:
|
|
124
|
-
|
|
125
|
-
type:
|
|
126
|
-
function:
|
|
127
|
-
name:
|
|
128
|
-
description:
|
|
129
|
-
parameters:
|
|
149
|
+
var chatRequestSchema = z2.object({
|
|
150
|
+
model: z2.string().min(1),
|
|
151
|
+
messages: z2.array(chatMessage).min(1),
|
|
152
|
+
stream: z2.boolean().optional(),
|
|
153
|
+
temperature: z2.number().min(0).max(2).optional(),
|
|
154
|
+
top_p: z2.number().min(0).max(1).optional(),
|
|
155
|
+
max_tokens: z2.number().int().positive().optional(),
|
|
156
|
+
stop: z2.union([z2.string(), z2.array(z2.string())]).optional(),
|
|
157
|
+
tools: z2.array(
|
|
158
|
+
z2.object({
|
|
159
|
+
type: z2.literal("function"),
|
|
160
|
+
function: z2.object({
|
|
161
|
+
name: z2.string(),
|
|
162
|
+
description: z2.string().optional(),
|
|
163
|
+
parameters: z2.record(z2.string(), z2.unknown()).optional()
|
|
130
164
|
})
|
|
131
165
|
})
|
|
132
166
|
).optional(),
|
|
133
|
-
tool_choice:
|
|
134
|
-
|
|
135
|
-
|
|
167
|
+
tool_choice: z2.union([
|
|
168
|
+
z2.enum(["auto", "none", "required"]),
|
|
169
|
+
z2.object({ type: z2.literal("function"), function: z2.object({ name: z2.string() }) })
|
|
136
170
|
]).optional(),
|
|
137
|
-
user:
|
|
171
|
+
user: z2.string().optional()
|
|
138
172
|
});
|
|
139
|
-
var positiveInt =
|
|
140
|
-
var quotaLimits =
|
|
173
|
+
var positiveInt = z2.number().int().positive();
|
|
174
|
+
var quotaLimits = z2.object({
|
|
141
175
|
tpm: positiveInt.optional(),
|
|
142
176
|
rpm: positiveInt.optional(),
|
|
143
177
|
tokens5h: positiveInt.optional(),
|
|
@@ -146,41 +180,41 @@ var quotaLimits = z.object({
|
|
|
146
180
|
requestsDaily: positiveInt.optional()
|
|
147
181
|
}).strict();
|
|
148
182
|
var SECRET_KEY = /^(api[-_]?key|secret|client[-_]?secret|(access|refresh|session|auth|bearer)?[-_]?token|password|passwd|cookies?|authorization|credentials?)$/i;
|
|
149
|
-
var accountConfig =
|
|
183
|
+
var accountConfig = z2.record(z2.string(), z2.unknown()).refine((config) => !Object.keys(config).some((key) => SECRET_KEY.test(key)), {
|
|
150
184
|
message: 'config must not contain credentials; send them in "secret" instead'
|
|
151
185
|
});
|
|
152
|
-
var subscriptionDate =
|
|
186
|
+
var subscriptionDate = z2.string().trim().refine(
|
|
153
187
|
(value) => /^\d{4}-\d{2}-\d{2}(T[\d:.]+(Z|[+-]\d{2}:?\d{2})?)?$/.test(value) && !Number.isNaN(Date.parse(value)),
|
|
154
188
|
{ message: "expected a date (YYYY-MM-DD) or an ISO timestamp" }
|
|
155
189
|
);
|
|
156
|
-
var subscriptionSchema =
|
|
157
|
-
plan:
|
|
190
|
+
var subscriptionSchema = z2.object({
|
|
191
|
+
plan: z2.string().trim().min(1).max(120).optional(),
|
|
158
192
|
paidAt: subscriptionDate.optional(),
|
|
159
193
|
renewsAt: subscriptionDate.optional(),
|
|
160
|
-
price:
|
|
161
|
-
amount:
|
|
162
|
-
currency:
|
|
163
|
-
period:
|
|
194
|
+
price: z2.object({
|
|
195
|
+
amount: z2.number().min(0).max(1e6),
|
|
196
|
+
currency: z2.string().trim().regex(/^[A-Za-z]{3}$/, "expected a 3-letter currency code").transform((c) => c.toUpperCase()),
|
|
197
|
+
period: z2.enum(["month", "year"])
|
|
164
198
|
}).strict().optional(),
|
|
165
|
-
notes:
|
|
199
|
+
notes: z2.string().trim().max(1e3).optional()
|
|
166
200
|
}).strict();
|
|
167
201
|
var accountFields = {
|
|
168
|
-
label:
|
|
169
|
-
enabled:
|
|
170
|
-
priority:
|
|
171
|
-
weight:
|
|
202
|
+
label: z2.string().trim().min(1).max(200),
|
|
203
|
+
enabled: z2.boolean().optional(),
|
|
204
|
+
priority: z2.number().int().min(0).max(1e6).optional(),
|
|
205
|
+
weight: z2.number().min(0).max(1e3).optional(),
|
|
172
206
|
limits: quotaLimits.optional(),
|
|
173
207
|
config: accountConfig.optional(),
|
|
174
208
|
/** API key / token. Encrypted at rest and never returned. */
|
|
175
|
-
secret:
|
|
209
|
+
secret: z2.string().min(1).max(1e5).optional()
|
|
176
210
|
};
|
|
177
|
-
var accountCreateSchema =
|
|
178
|
-
var accountPatchSchema =
|
|
211
|
+
var accountCreateSchema = z2.object({ provider: providerKind, ...accountFields, subscription: subscriptionSchema.optional() }).strict();
|
|
212
|
+
var accountPatchSchema = z2.object({
|
|
179
213
|
...accountFields,
|
|
180
214
|
label: accountFields.label.optional(),
|
|
181
215
|
subscription: subscriptionSchema.nullable().optional()
|
|
182
216
|
}).strict();
|
|
183
|
-
var routesUpdateSchema =
|
|
217
|
+
var routesUpdateSchema = z2.object({ routes: z2.array(routeSchema).max(200), defaultRoute: z2.string().min(1).optional() }).strict().superRefine((body, ctx) => {
|
|
184
218
|
const seen = /* @__PURE__ */ new Set();
|
|
185
219
|
body.routes.forEach((route, index) => {
|
|
186
220
|
if (seen.has(route.name)) {
|
|
@@ -201,14 +235,14 @@ var routesUpdateSchema = z.object({ routes: z.array(routeSchema).max(200), defau
|
|
|
201
235
|
}
|
|
202
236
|
});
|
|
203
237
|
var taskText = {
|
|
204
|
-
title:
|
|
205
|
-
description:
|
|
206
|
-
acceptance:
|
|
207
|
-
notes:
|
|
208
|
-
dependsOn:
|
|
209
|
-
priority:
|
|
238
|
+
title: z2.string().trim().min(1).max(300),
|
|
239
|
+
description: z2.string().max(5e4),
|
|
240
|
+
acceptance: z2.array(z2.string().trim().min(1).max(2e3)).max(100),
|
|
241
|
+
notes: z2.string().max(5e4),
|
|
242
|
+
dependsOn: z2.array(z2.string().min(1)).max(500),
|
|
243
|
+
priority: z2.number().finite()
|
|
210
244
|
};
|
|
211
|
-
var taskCreateSchema =
|
|
245
|
+
var taskCreateSchema = z2.object({
|
|
212
246
|
id: taskIdSchema,
|
|
213
247
|
title: taskText.title,
|
|
214
248
|
description: taskText.description.optional(),
|
|
@@ -216,30 +250,30 @@ var taskCreateSchema = z.object({
|
|
|
216
250
|
priority: taskText.priority.optional(),
|
|
217
251
|
acceptance: taskText.acceptance.optional()
|
|
218
252
|
}).strict();
|
|
219
|
-
var taskPatchSchema =
|
|
253
|
+
var taskPatchSchema = z2.object({
|
|
220
254
|
title: taskText.title.optional(),
|
|
221
255
|
description: taskText.description.nullable().optional(),
|
|
222
256
|
dependsOn: taskText.dependsOn.optional(),
|
|
223
257
|
priority: taskText.priority.nullable().optional(),
|
|
224
258
|
acceptance: taskText.acceptance.nullable().optional(),
|
|
225
259
|
notes: taskText.notes.nullable().optional(),
|
|
226
|
-
status:
|
|
260
|
+
status: z2.enum(TASK_STATUSES).optional()
|
|
227
261
|
}).strict().refine((patch) => Object.values(patch).some((v) => v !== void 0), {
|
|
228
262
|
message: "send at least one field to change"
|
|
229
263
|
});
|
|
230
|
-
var runnerStartSchema =
|
|
231
|
-
var goalStartSchema =
|
|
232
|
-
objective:
|
|
233
|
-
maxRounds:
|
|
234
|
-
maxTasks:
|
|
235
|
-
maxTokens:
|
|
236
|
-
dryRun:
|
|
264
|
+
var runnerStartSchema = z2.object({ taskId: z2.string().min(1).optional() }).strict();
|
|
265
|
+
var goalStartSchema = z2.object({
|
|
266
|
+
objective: z2.string().trim().min(1).max(4e3),
|
|
267
|
+
maxRounds: z2.number().int().min(1).max(20).optional(),
|
|
268
|
+
maxTasks: z2.number().int().min(1).max(100).optional(),
|
|
269
|
+
maxTokens: z2.number().int().min(1e3).optional(),
|
|
270
|
+
dryRun: z2.boolean().optional()
|
|
237
271
|
}).strict();
|
|
238
|
-
var timeseriesQuerySchema =
|
|
239
|
-
minutes:
|
|
240
|
-
bucketSec:
|
|
272
|
+
var timeseriesQuerySchema = z2.object({
|
|
273
|
+
minutes: z2.coerce.number().int().min(1).max(7 * 24 * 60).default(60),
|
|
274
|
+
bucketSec: z2.coerce.number().int().min(1).max(86400).default(60)
|
|
241
275
|
});
|
|
242
|
-
var limitQuerySchema = (fallback, max = 1e3) =>
|
|
276
|
+
var limitQuerySchema = (fallback, max = 1e3) => z2.object({ limit: z2.coerce.number().int().min(1).max(max).default(fallback) });
|
|
243
277
|
function registerGoalRoutes(app, engine, options) {
|
|
244
278
|
const { audit } = engine;
|
|
245
279
|
const unavailable = (reply) => sendApiError(
|
|
@@ -281,7 +315,7 @@ function registerGoalRoutes(app, engine, options) {
|
|
|
281
315
|
app.post("/api/goals", async (request, reply) => {
|
|
282
316
|
const parsed = goalStartSchema.safeParse(request.body);
|
|
283
317
|
if (!parsed.success) {
|
|
284
|
-
return sendApiError(reply, 400, "invalid_body",
|
|
318
|
+
return sendApiError(reply, 400, "invalid_body", z3.prettifyError(parsed.error));
|
|
285
319
|
}
|
|
286
320
|
const goals = control(reply);
|
|
287
321
|
if (!goals) return reply;
|
|
@@ -385,7 +419,7 @@ function registerTaskRoutes(app, engine, options) {
|
|
|
385
419
|
app.post("/api/tasks", async (request, reply) => {
|
|
386
420
|
const parsed = taskCreateSchema.safeParse(request.body);
|
|
387
421
|
if (!parsed.success) {
|
|
388
|
-
return sendApiError(reply, 400, "invalid_body",
|
|
422
|
+
return sendApiError(reply, 400, "invalid_body", z4.prettifyError(parsed.error));
|
|
389
423
|
}
|
|
390
424
|
const brain = writable(reply);
|
|
391
425
|
if (isReply(brain)) return brain;
|
|
@@ -400,7 +434,7 @@ function registerTaskRoutes(app, engine, options) {
|
|
|
400
434
|
app.patch("/api/tasks/:id", async (request, reply) => {
|
|
401
435
|
const parsed = taskPatchSchema.safeParse(request.body);
|
|
402
436
|
if (!parsed.success) {
|
|
403
|
-
return sendApiError(reply, 400, "invalid_body",
|
|
437
|
+
return sendApiError(reply, 400, "invalid_body", z4.prettifyError(parsed.error));
|
|
404
438
|
}
|
|
405
439
|
const brain = writable(reply);
|
|
406
440
|
if (isReply(brain)) return brain;
|
|
@@ -443,7 +477,7 @@ function isReply(value) {
|
|
|
443
477
|
var EMPTY_GRAPH = { version: 1, tasks: [] };
|
|
444
478
|
var IDLE = { state: "idle" };
|
|
445
479
|
function invalid(reply, error) {
|
|
446
|
-
return sendApiError(reply, 400, "invalid_body",
|
|
480
|
+
return sendApiError(reply, 400, "invalid_body", z5.prettifyError(error));
|
|
447
481
|
}
|
|
448
482
|
function registerApiRoutes(app, engine, options) {
|
|
449
483
|
const { accounts, events, audit, quota, keyring } = engine;
|
|
@@ -460,6 +494,10 @@ function registerApiRoutes(app, engine, options) {
|
|
|
460
494
|
const parsed = accountCreateSchema.safeParse(request.body);
|
|
461
495
|
if (!parsed.success) return invalid(reply, parsed.error);
|
|
462
496
|
const { secret, ...input } = parsed.data;
|
|
497
|
+
const configIssues = input.config ? apiConfigIssues(input.provider, input.config) : [];
|
|
498
|
+
if (configIssues.length > 0) {
|
|
499
|
+
return sendApiError(reply, 400, "invalid_body", configIssues.join("; "));
|
|
500
|
+
}
|
|
463
501
|
if (input.provider === "gemini-web" && !engine.config.experimental.geminiWeb) {
|
|
464
502
|
return sendApiError(
|
|
465
503
|
reply,
|
|
@@ -489,6 +527,15 @@ function registerApiRoutes(app, engine, options) {
|
|
|
489
527
|
if (!existing) return sendApiError(reply, 404, "not_found", "Account not found");
|
|
490
528
|
const { secret, ...fields } = parsed.data;
|
|
491
529
|
const patch = { ...fields };
|
|
530
|
+
if (fields.config) {
|
|
531
|
+
const configIssues = apiConfigIssues(existing.provider, fields.config, existing.config);
|
|
532
|
+
if (configIssues.length > 0) {
|
|
533
|
+
return sendApiError(reply, 400, "invalid_body", configIssues.join("; "));
|
|
534
|
+
}
|
|
535
|
+
patch.config = mergeApiConfig(existing.provider, existing.config, fields.config);
|
|
536
|
+
const rebind = endpointRebindIssue(existing, patch.config, secret !== void 0);
|
|
537
|
+
if (rebind) return sendApiError(reply, 400, "secret_required", rebind);
|
|
538
|
+
}
|
|
492
539
|
const enabled = fields.enabled ?? existing.enabled;
|
|
493
540
|
if (!enabled) {
|
|
494
541
|
patch.status = "disabled";
|
|
@@ -536,9 +583,6 @@ function registerApiRoutes(app, engine, options) {
|
|
|
536
583
|
return { connection: await engine.connections.check(account) };
|
|
537
584
|
});
|
|
538
585
|
app.post("/api/accounts/:id/connect", async (request, reply) => {
|
|
539
|
-
if (!request.headers["content-type"]?.toLowerCase().startsWith("application/json")) {
|
|
540
|
-
return sendApiError(reply, 415, "json_required", "Send Content-Type: application/json");
|
|
541
|
-
}
|
|
542
586
|
const account = accounts.get(request.params.id);
|
|
543
587
|
if (!account) return sendApiError(reply, 404, "not_found", "Account not found");
|
|
544
588
|
if (connectionMethod(account.provider) !== "cli-login") {
|
|
@@ -716,7 +760,7 @@ function registerAuthRoutes(app, login) {
|
|
|
716
760
|
return reply.header("Cache-Control", "no-store").header("Set-Cookie", cookie("dc_session", "", 0, secure)).code(204).send();
|
|
717
761
|
});
|
|
718
762
|
for (const provider of ["google", "github"]) {
|
|
719
|
-
app.get(`/api/auth/${provider}/start`, async (
|
|
763
|
+
app.get(`/api/auth/${provider}/start`, async (request, reply) => {
|
|
720
764
|
if (!login?.options.providers[provider])
|
|
721
765
|
return sendApiError(
|
|
722
766
|
reply,
|
|
@@ -725,7 +769,7 @@ function registerAuthRoutes(app, login) {
|
|
|
725
769
|
"This sign-in provider is not configured."
|
|
726
770
|
);
|
|
727
771
|
try {
|
|
728
|
-
const flow = login.begin(provider);
|
|
772
|
+
const flow = login.begin(provider, request.ip);
|
|
729
773
|
return reply.header("Cache-Control", "no-store").header("Referrer-Policy", "no-referrer").header("Set-Cookie", cookie("dc_login", flow.binding, 600, secure)).redirect(flow.url);
|
|
730
774
|
} catch {
|
|
731
775
|
return sendApiError(reply, 429, "login_busy", "Sign-in is busy. Try again shortly.");
|
|
@@ -735,7 +779,7 @@ function registerAuthRoutes(app, login) {
|
|
|
735
779
|
reply.header("Cache-Control", "no-store").header("Referrer-Policy", "no-referrer");
|
|
736
780
|
if (!login)
|
|
737
781
|
return sendApiError(reply, 503, "login_not_configured", "Sign-in is not configured.");
|
|
738
|
-
const parsed =
|
|
782
|
+
const parsed = z6.object({ state: z6.string().min(1).max(200), code: z6.string().min(1).max(4096) }).safeParse(request.query);
|
|
739
783
|
const binding = authCookie(request, "dc_login");
|
|
740
784
|
if (!parsed.success || !binding)
|
|
741
785
|
return reply.redirect(`${login.options.origin}/#/login?error=signin_failed`);
|
|
@@ -835,7 +879,7 @@ function registerV1Routes(app, engine) {
|
|
|
835
879
|
const parsed = chatRequestSchema.safeParse(request.body);
|
|
836
880
|
if (!parsed.success) {
|
|
837
881
|
return sendOpenAIError(reply, 400, {
|
|
838
|
-
message:
|
|
882
|
+
message: z7.prettifyError(parsed.error),
|
|
839
883
|
type: "invalid_request_error",
|
|
840
884
|
code: "invalid_body"
|
|
841
885
|
});
|
|
@@ -879,12 +923,43 @@ function pathOf(url) {
|
|
|
879
923
|
const q = url.indexOf("?");
|
|
880
924
|
return q === -1 ? url : url.slice(0, q);
|
|
881
925
|
}
|
|
882
|
-
function
|
|
926
|
+
function normalisedPath(url) {
|
|
883
927
|
const path2 = pathOf(url);
|
|
928
|
+
try {
|
|
929
|
+
return decodeURIComponent(path2).toLowerCase();
|
|
930
|
+
} catch {
|
|
931
|
+
return path2.toLowerCase();
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
function surfaceOf(url) {
|
|
935
|
+
const path2 = normalisedPath(url);
|
|
884
936
|
if (path2 === "/v1" || path2.startsWith("/v1/")) return "v1";
|
|
885
937
|
if (path2 === "/api" || path2.startsWith("/api/")) return "api";
|
|
886
938
|
return "other";
|
|
887
939
|
}
|
|
940
|
+
var PUBLIC_ROUTES = /* @__PURE__ */ new Set([
|
|
941
|
+
"/api/auth/session",
|
|
942
|
+
"/api/auth/logout",
|
|
943
|
+
"/api/auth/google/start",
|
|
944
|
+
"/api/auth/google/callback",
|
|
945
|
+
"/api/auth/github/start",
|
|
946
|
+
"/api/auth/github/callback"
|
|
947
|
+
]);
|
|
948
|
+
var STATIC_ROUTES = /* @__PURE__ */ new Set(["/", "/*"]);
|
|
949
|
+
var SAFE_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
|
|
950
|
+
function splitHost(header) {
|
|
951
|
+
const match = /^(\[[0-9a-f:.]+\]|[^:/\\@\s]+)(?::(\d{1,5}))?$/i.exec(header.trim());
|
|
952
|
+
if (!match?.[1]) return void 0;
|
|
953
|
+
return { name: match[1].toLowerCase(), port: match[2] ?? "" };
|
|
954
|
+
}
|
|
955
|
+
function originOf(value) {
|
|
956
|
+
try {
|
|
957
|
+
const url = new URL(value);
|
|
958
|
+
return url.origin === "null" ? void 0 : url.origin;
|
|
959
|
+
} catch {
|
|
960
|
+
return void 0;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
888
963
|
function redactUrl(url) {
|
|
889
964
|
return url.replace(/([?&](?:token|code|state|error_description)=)[^&]*/gi, "$1[redacted]");
|
|
890
965
|
}
|
|
@@ -914,9 +989,53 @@ async function buildGateway(engine, options = {}) {
|
|
|
914
989
|
const app = Fastify({ logger: loggerOption(options.logger), bodyLimit: 10 * 1024 * 1024 });
|
|
915
990
|
const login = options.login === false ? void 0 : options.login ?? loginFromEnv(process.env);
|
|
916
991
|
if (login) app.addHook("onClose", async () => login.clear());
|
|
992
|
+
const bindHost = (options.host ?? engine.config.server.host).toLowerCase();
|
|
993
|
+
const loopbackBind = LOOPBACK.has(bindHost);
|
|
994
|
+
const extraOrigins = [
|
|
995
|
+
...options.dev ? DEFAULT_CORS_ORIGINS : [],
|
|
996
|
+
...options.corsOrigins ?? [],
|
|
997
|
+
...login ? [login.options.origin] : []
|
|
998
|
+
].map(originOf).filter((origin) => origin !== void 0);
|
|
999
|
+
const allowedOrigins = new Set(extraOrigins);
|
|
1000
|
+
const extraHosts = new Set(
|
|
1001
|
+
[...options.corsOrigins ?? [], ...login ? [login.options.origin] : []].map(originOf).filter((origin) => origin !== void 0).map((origin) => new URL(origin).host.toLowerCase())
|
|
1002
|
+
);
|
|
1003
|
+
function hostAllowed(request) {
|
|
1004
|
+
if (!loopbackBind) return true;
|
|
1005
|
+
const header = request.headers.host;
|
|
1006
|
+
if (!header) return false;
|
|
1007
|
+
if (extraHosts.has(header.toLowerCase())) return true;
|
|
1008
|
+
const parsed = splitHost(header);
|
|
1009
|
+
if (!parsed || !["127.0.0.1", "localhost", "[::1]"].includes(parsed.name)) return false;
|
|
1010
|
+
const actual = request.raw.socket?.localPort;
|
|
1011
|
+
return actual === void 0 || Number(parsed.port || 80) === actual;
|
|
1012
|
+
}
|
|
1013
|
+
function originAllowed(request) {
|
|
1014
|
+
const origin = request.headers.origin;
|
|
1015
|
+
if (origin === void 0) return true;
|
|
1016
|
+
const normalised = originOf(origin);
|
|
1017
|
+
if (!normalised) return false;
|
|
1018
|
+
if (allowedOrigins.has(normalised)) return true;
|
|
1019
|
+
const host = request.headers.host?.toLowerCase();
|
|
1020
|
+
return host !== void 0 && new URL(normalised).host.toLowerCase() === host;
|
|
1021
|
+
}
|
|
1022
|
+
app.addHook("onRequest", async (request, reply) => {
|
|
1023
|
+
const surface = surfaceOf(request.routeOptions.url ?? request.url);
|
|
1024
|
+
const reject = (status, code, message) => surface === "v1" ? sendOpenAIError(reply, status, { message, type: "invalid_request_error", code }) : sendApiError(reply, status, code, message);
|
|
1025
|
+
if (!hostAllowed(request)) return reject(403, "invalid_host", "Unexpected Host header.");
|
|
1026
|
+
if (surface !== "api" || SAFE_METHODS.has(request.method)) return;
|
|
1027
|
+
if (!originAllowed(request)) {
|
|
1028
|
+
return reject(403, "invalid_origin", "Requests from this origin are not allowed.");
|
|
1029
|
+
}
|
|
1030
|
+
if (PUBLIC_ROUTES.has(request.routeOptions.url ?? "")) return;
|
|
1031
|
+
if (request.method !== "POST") return;
|
|
1032
|
+
if (!request.headers["content-type"]?.toLowerCase().startsWith("application/json")) {
|
|
1033
|
+
return reject(415, "json_required", "Send Content-Type: application/json");
|
|
1034
|
+
}
|
|
1035
|
+
});
|
|
917
1036
|
await app.register(cors, {
|
|
918
|
-
origin: [...DEFAULT_CORS_ORIGINS, ...options.corsOrigins ?? []],
|
|
919
|
-
methods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
|
|
1037
|
+
origin: [...options.dev ? DEFAULT_CORS_ORIGINS : [], ...options.corsOrigins ?? []],
|
|
1038
|
+
methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
|
920
1039
|
allowedHeaders: ["content-type", "authorization"],
|
|
921
1040
|
exposedHeaders: EXPOSED_HEADERS
|
|
922
1041
|
});
|
|
@@ -924,16 +1043,21 @@ async function buildGateway(engine, options = {}) {
|
|
|
924
1043
|
if (token || login) {
|
|
925
1044
|
app.addHook("onRequest", async (request, reply) => {
|
|
926
1045
|
if (request.method === "OPTIONS") return;
|
|
1046
|
+
const route = request.routeOptions.url;
|
|
1047
|
+
if (route !== void 0) {
|
|
1048
|
+
if (PUBLIC_ROUTES.has(route)) return;
|
|
1049
|
+
if (STATIC_ROUTES.has(route) && (request.method === "GET" || request.method === "HEAD"))
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
927
1052
|
const surface = surfaceOf(request.url);
|
|
928
|
-
|
|
929
|
-
if (pathOf(request.url).startsWith("/api/auth/")) return;
|
|
1053
|
+
const isV1 = route === "/v1" || route?.startsWith("/v1/") || surface === "v1";
|
|
930
1054
|
let provided = bearer(request);
|
|
931
|
-
if (!provided &&
|
|
1055
|
+
if (!provided && route === "/api/events") {
|
|
932
1056
|
const query = request.query;
|
|
933
1057
|
if (typeof query?.token === "string") provided = query.token;
|
|
934
1058
|
}
|
|
935
1059
|
if (provided && token && safeEqual(provided, token)) return;
|
|
936
|
-
if (
|
|
1060
|
+
if (!isV1 && login?.user(authCookie(request, "dc_session"))) {
|
|
937
1061
|
if (!["GET", "HEAD"].includes(request.method) && request.headers.origin !== login.options.origin) {
|
|
938
1062
|
return sendApiError(
|
|
939
1063
|
reply,
|
|
@@ -945,7 +1069,7 @@ async function buildGateway(engine, options = {}) {
|
|
|
945
1069
|
return;
|
|
946
1070
|
}
|
|
947
1071
|
const message = "Missing or invalid bearer token";
|
|
948
|
-
if (
|
|
1072
|
+
if (isV1) {
|
|
949
1073
|
return sendOpenAIError(reply, 401, {
|
|
950
1074
|
message,
|
|
951
1075
|
type: "authentication_error",
|
|
@@ -1002,14 +1126,15 @@ async function buildGateway(engine, options = {}) {
|
|
|
1002
1126
|
});
|
|
1003
1127
|
registerV1Routes(app, engine);
|
|
1004
1128
|
registerAuthRoutes(app, login);
|
|
1129
|
+
registerAccountRoutes(app, options.account);
|
|
1005
1130
|
registerApiRoutes(app, engine, options);
|
|
1006
1131
|
registerEventRoutes(app, engine, options.heartbeatMs ?? 15e3);
|
|
1007
1132
|
return app;
|
|
1008
1133
|
}
|
|
1009
1134
|
var LOOPBACK = /* @__PURE__ */ new Set(["127.0.0.1", "::1", "localhost"]);
|
|
1010
1135
|
async function startGateway(engine, options = {}) {
|
|
1011
|
-
const app = await buildGateway(engine, options);
|
|
1012
1136
|
const host = options.host ?? engine.config.server.host;
|
|
1137
|
+
const app = await buildGateway(engine, { ...options, host });
|
|
1013
1138
|
const port = options.port ?? engine.config.server.port;
|
|
1014
1139
|
if (!engine.config.server.authToken && !LOOPBACK.has(host)) {
|
|
1015
1140
|
app.log.warn(
|
|
@@ -1215,10 +1340,9 @@ var GatewayClient = class {
|
|
|
1215
1340
|
}
|
|
1216
1341
|
async request(method, path2, body, options = {}) {
|
|
1217
1342
|
const init = { method };
|
|
1218
|
-
if (body !== void 0)
|
|
1219
|
-
|
|
1343
|
+
if (body !== void 0) init.body = JSON.stringify(body);
|
|
1344
|
+
if (body !== void 0 || method !== "GET")
|
|
1220
1345
|
init.headers = { "content-type": "application/json" };
|
|
1221
|
-
}
|
|
1222
1346
|
const res = await this.fetch(path2, init, { timeoutMs: 1e4, ...options });
|
|
1223
1347
|
if (!res.ok) throw await errorFrom(res);
|
|
1224
1348
|
if (res.status === 204) return void 0;
|
|
@@ -1541,18 +1665,25 @@ async function startRuntime(options) {
|
|
|
1541
1665
|
...projectRoot ? { projectRoot } : {},
|
|
1542
1666
|
...options.config ? { config: options.config } : {}
|
|
1543
1667
|
});
|
|
1668
|
+
let account;
|
|
1544
1669
|
try {
|
|
1545
1670
|
const project = projectRoot ? wireProject(engine, projectRoot, { env: options.env }) : void 0;
|
|
1546
1671
|
const wantDashboard = options.dashboard !== false && engine.config.server.dashboard;
|
|
1547
1672
|
const dashboardDir = wantDashboard ? resolveDashboardDir(options.env) : void 0;
|
|
1548
1673
|
const bindHost = options.host ?? engine.config.server.host;
|
|
1549
1674
|
const loginLauncher = LOOPBACK_HOSTS.has(bindHost) ? {
|
|
1550
|
-
launch: async (
|
|
1551
|
-
launched: await launchLoginTerminal(
|
|
1675
|
+
launch: async (account2) => ({
|
|
1676
|
+
launched: await launchLoginTerminal(account2.id, { env: options.env })
|
|
1552
1677
|
})
|
|
1553
1678
|
} : void 0;
|
|
1679
|
+
account = LOOPBACK_HOSTS.has(bindHost) ? createAccountControl({
|
|
1680
|
+
home: options.home,
|
|
1681
|
+
env: options.env,
|
|
1682
|
+
open: (url) => openBrowser(url)
|
|
1683
|
+
}) : void 0;
|
|
1554
1684
|
const app = await startGateway(engine, {
|
|
1555
1685
|
logger: options.logger ?? false,
|
|
1686
|
+
...account ? { account } : {},
|
|
1556
1687
|
...options.loginLauncher ?? loginLauncher ? { loginLauncher: options.loginLauncher ?? loginLauncher } : {},
|
|
1557
1688
|
...dashboardDir ? { dashboardDir } : {},
|
|
1558
1689
|
...project ? { brain: project.source, runner: project.runner, goals: project.goals } : {},
|
|
@@ -1582,6 +1713,7 @@ async function startRuntime(options) {
|
|
|
1582
1713
|
const active = goals?.activeGoalId;
|
|
1583
1714
|
if (active) await goals?.cancel(active);
|
|
1584
1715
|
await runner?.stop();
|
|
1716
|
+
await account?.close();
|
|
1585
1717
|
await app.close();
|
|
1586
1718
|
} finally {
|
|
1587
1719
|
engine.close();
|
|
@@ -1589,6 +1721,7 @@ async function startRuntime(options) {
|
|
|
1589
1721
|
}
|
|
1590
1722
|
};
|
|
1591
1723
|
} catch (err) {
|
|
1724
|
+
await account?.close();
|
|
1592
1725
|
engine.close();
|
|
1593
1726
|
throw err;
|
|
1594
1727
|
}
|
|
@@ -1611,4 +1744,4 @@ export {
|
|
|
1611
1744
|
resolveProjectRoot,
|
|
1612
1745
|
startRuntime
|
|
1613
1746
|
};
|
|
1614
|
-
//# sourceMappingURL=chunk-
|
|
1747
|
+
//# sourceMappingURL=chunk-KUY3QHGS.js.map
|