@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.
Files changed (73) hide show
  1. package/dist/{ChatApp-CJBICQGA.js → ChatApp-Z6PQIZ5J.js} +7 -6
  2. package/dist/{ChatApp-CJBICQGA.js.map → ChatApp-Z6PQIZ5J.js.map} +1 -1
  3. package/dist/{account-QWDPJWAA.js → account-RTPS2V6O.js} +4 -3
  4. package/dist/{accounts-IQMR72FC.js → accounts-IYQ4ZRL7.js} +6 -5
  5. package/dist/{budget-XANOUVWO.js → budget-N2ZB66FF.js} +5 -4
  6. package/dist/{budget-XANOUVWO.js.map → budget-N2ZB66FF.js.map} +1 -1
  7. package/dist/{chat-KDDRNC5V.js → chat-6TX6JX45.js} +9 -8
  8. package/dist/{chat-KDDRNC5V.js.map → chat-6TX6JX45.js.map} +1 -1
  9. package/dist/chunk-732GIHRQ.js +23 -0
  10. package/dist/chunk-732GIHRQ.js.map +1 -0
  11. package/dist/{chunk-AZKACMME.js → chunk-BJTXMET2.js} +2 -2
  12. package/dist/{chunk-FYPMA55O.js → chunk-KUY3QHGS.js} +239 -106
  13. package/dist/chunk-KUY3QHGS.js.map +1 -0
  14. package/dist/{chunk-JLATEHS7.js → chunk-LEU46DGH.js} +2 -2
  15. package/dist/{chunk-HSBJDV3O.js → chunk-QKY3OKVG.js} +309 -23
  16. package/dist/chunk-QKY3OKVG.js.map +1 -0
  17. package/dist/{chunk-WQ7MEWDF.js → chunk-UEV5K3DH.js} +10 -4
  18. package/dist/chunk-UEV5K3DH.js.map +1 -0
  19. package/dist/{chunk-44AFJL2X.js → chunk-UNK3EQD6.js} +6 -5
  20. package/dist/chunk-UNK3EQD6.js.map +1 -0
  21. package/dist/{chunk-W7GPBEBZ.js → chunk-WAARDGCZ.js} +5 -21
  22. package/dist/chunk-WAARDGCZ.js.map +1 -0
  23. package/dist/{chunk-PGAJIGUF.js → chunk-YNAMNQLW.js} +3 -3
  24. package/dist/{config-YTUPIYZT.js → config-YQKY2AA4.js} +4 -3
  25. package/dist/{config-YTUPIYZT.js.map → config-YQKY2AA4.js.map} +1 -1
  26. package/dist/dashboard/assets/Accounts-DXiGsutB.js +1 -0
  27. package/dist/dashboard/assets/{Badge-Z4RBdO9j.js → Badge-DUGKlx3Z.js} +1 -1
  28. package/dist/dashboard/assets/{Callout-w8BTYh4k.js → Callout-1E8Wsl9W.js} +1 -1
  29. package/dist/dashboard/assets/{Goals-Bw02to72.js → Goals-kL4VAxw3.js} +1 -1
  30. package/dist/dashboard/assets/{Library-DK7mlpRb.js → Library-DZxBVUo_.js} +1 -1
  31. package/dist/dashboard/assets/Markdown-CGgIydUh.js +71 -0
  32. package/dist/dashboard/assets/{Panes-_KTf8pbZ.js → Panes-C-TJekjs.js} +1 -1
  33. package/dist/dashboard/assets/{RoutesPage-QV0oPRW9.js → RoutesPage-DWYm9tW8.js} +1 -1
  34. package/dist/dashboard/assets/{Runner-CkHBLQl0.js → Runner-CmHBjECR.js} +1 -1
  35. package/dist/dashboard/assets/{Settings-BLz2gTBR.js → Settings-BANphxva.js} +1 -1
  36. package/dist/dashboard/assets/{Tasks-BiUQSTpt.js → Tasks-cSx1PKyQ.js} +1 -1
  37. package/dist/dashboard/assets/{Traffic-BVfBuC70.js → Traffic-DEAuM6jq.js} +1 -1
  38. package/dist/dashboard/assets/{Workspace-CJTgiiU5.js → Workspace-BQFjc1jH.js} +1 -1
  39. package/dist/dashboard/assets/index-B8kld9xo.js +104 -0
  40. package/dist/dashboard/assets/{task-errors-Daqwi0ue.js → task-errors-r-WYZ_S3.js} +1 -1
  41. package/dist/dashboard/index.html +2 -2
  42. package/dist/{dist-37VQSHHA.js → dist-PIC255RX.js} +20 -2
  43. package/dist/{doctor-PYUQRRCB.js → doctor-PQC7JQPP.js} +4 -3
  44. package/dist/{doctor-PYUQRRCB.js.map → doctor-PQC7JQPP.js.map} +1 -1
  45. package/dist/{goal-SXZUDUCL.js → goal-STLEU7C7.js} +4 -3
  46. package/dist/{goal-SXZUDUCL.js.map → goal-STLEU7C7.js.map} +1 -1
  47. package/dist/index.js +31 -31
  48. package/dist/{init-Z2AFQEEP.js → init-NHU5LJSS.js} +4 -3
  49. package/dist/{init-Z2AFQEEP.js.map → init-NHU5LJSS.js.map} +1 -1
  50. package/dist/{run-AOS7L3RT.js → run-7HWSHMRJ.js} +4 -3
  51. package/dist/{run-AOS7L3RT.js.map → run-7HWSHMRJ.js.map} +1 -1
  52. package/dist/runtime.js +3 -2
  53. package/dist/{start-CEPXKZUE.js → start-WVAEAQWL.js} +4 -3
  54. package/dist/{start-CEPXKZUE.js.map → start-WVAEAQWL.js.map} +1 -1
  55. package/dist/{status-WNJ3GGKU.js → status-ZRHPFLFT.js} +5 -4
  56. package/dist/{tasks-TFUTUMWB.js → tasks-JVWXUNXN.js} +5 -4
  57. package/dist/{tasks-TFUTUMWB.js.map → tasks-JVWXUNXN.js.map} +1 -1
  58. package/package.json +6 -6
  59. package/dist/chunk-44AFJL2X.js.map +0 -1
  60. package/dist/chunk-FYPMA55O.js.map +0 -1
  61. package/dist/chunk-HSBJDV3O.js.map +0 -1
  62. package/dist/chunk-W7GPBEBZ.js.map +0 -1
  63. package/dist/chunk-WQ7MEWDF.js.map +0 -1
  64. package/dist/dashboard/assets/Accounts-cq8RLMoI.js +0 -1
  65. package/dist/dashboard/assets/Markdown-DCZ4Awcc.js +0 -69
  66. package/dist/dashboard/assets/index-BDBa5cb0.js +0 -104
  67. /package/dist/{account-QWDPJWAA.js.map → account-RTPS2V6O.js.map} +0 -0
  68. /package/dist/{accounts-IQMR72FC.js.map → accounts-IYQ4ZRL7.js.map} +0 -0
  69. /package/dist/{chunk-AZKACMME.js.map → chunk-BJTXMET2.js.map} +0 -0
  70. /package/dist/{chunk-JLATEHS7.js.map → chunk-LEU46DGH.js.map} +0 -0
  71. /package/dist/{chunk-PGAJIGUF.js.map → chunk-YNAMNQLW.js.map} +0 -0
  72. /package/dist/{dist-37VQSHHA.js.map → dist-PIC255RX.js.map} +0 -0
  73. /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-HSBJDV3O.js";
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 z5 } from "zod";
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 providerKind = z.enum(PROVIDER_KINDS);
93
- var contentPart = z.discriminatedUnion("type", [
94
- z.object({ type: z.literal("text"), text: z.string() }),
95
- z.object({
96
- type: z.literal("image_url"),
97
- image_url: z.object({
98
- url: z.string(),
99
- detail: z.enum(["auto", "low", "high"]).optional()
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 = z.object({
104
- id: z.string(),
105
- type: z.literal("function"),
106
- function: z.object({ name: z.string(), arguments: z.string() })
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 = z.object({
109
- role: z.enum(["system", "user", "assistant", "tool"]),
110
- content: z.union([z.string(), z.array(contentPart), z.null()]),
111
- name: z.string().optional(),
112
- tool_call_id: z.string().optional(),
113
- tool_calls: z.array(toolCall).optional()
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 = z.object({
116
- model: z.string().min(1),
117
- messages: z.array(chatMessage).min(1),
118
- stream: z.boolean().optional(),
119
- temperature: z.number().min(0).max(2).optional(),
120
- top_p: z.number().min(0).max(1).optional(),
121
- max_tokens: z.number().int().positive().optional(),
122
- stop: z.union([z.string(), z.array(z.string())]).optional(),
123
- tools: z.array(
124
- z.object({
125
- type: z.literal("function"),
126
- function: z.object({
127
- name: z.string(),
128
- description: z.string().optional(),
129
- parameters: z.record(z.string(), z.unknown()).optional()
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: z.union([
134
- z.enum(["auto", "none", "required"]),
135
- z.object({ type: z.literal("function"), function: z.object({ name: z.string() }) })
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: z.string().optional()
171
+ user: z2.string().optional()
138
172
  });
139
- var positiveInt = z.number().int().positive();
140
- var quotaLimits = z.object({
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 = z.record(z.string(), z.unknown()).refine((config) => !Object.keys(config).some((key) => SECRET_KEY.test(key)), {
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 = z.string().trim().refine(
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 = z.object({
157
- plan: z.string().trim().min(1).max(120).optional(),
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: z.object({
161
- amount: z.number().min(0).max(1e6),
162
- currency: z.string().trim().regex(/^[A-Za-z]{3}$/, "expected a 3-letter currency code").transform((c) => c.toUpperCase()),
163
- period: z.enum(["month", "year"])
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: z.string().trim().max(1e3).optional()
199
+ notes: z2.string().trim().max(1e3).optional()
166
200
  }).strict();
167
201
  var accountFields = {
168
- label: z.string().trim().min(1).max(200),
169
- enabled: z.boolean().optional(),
170
- priority: z.number().int().min(0).max(1e6).optional(),
171
- weight: z.number().min(0).max(1e3).optional(),
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: z.string().min(1).max(1e5).optional()
209
+ secret: z2.string().min(1).max(1e5).optional()
176
210
  };
177
- var accountCreateSchema = z.object({ provider: providerKind, ...accountFields, subscription: subscriptionSchema.optional() }).strict();
178
- var accountPatchSchema = z.object({
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 = z.object({ routes: z.array(routeSchema).max(200), defaultRoute: z.string().min(1).optional() }).strict().superRefine((body, ctx) => {
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: z.string().trim().min(1).max(300),
205
- description: z.string().max(5e4),
206
- acceptance: z.array(z.string().trim().min(1).max(2e3)).max(100),
207
- notes: z.string().max(5e4),
208
- dependsOn: z.array(z.string().min(1)).max(500),
209
- priority: z.number().finite()
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 = z.object({
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 = z.object({
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: z.enum(TASK_STATUSES).optional()
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 = z.object({ taskId: z.string().min(1).optional() }).strict();
231
- var goalStartSchema = z.object({
232
- objective: z.string().trim().min(1).max(4e3),
233
- maxRounds: z.number().int().min(1).max(20).optional(),
234
- maxTasks: z.number().int().min(1).max(100).optional(),
235
- maxTokens: z.number().int().min(1e3).optional(),
236
- dryRun: z.boolean().optional()
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 = z.object({
239
- minutes: z.coerce.number().int().min(1).max(7 * 24 * 60).default(60),
240
- bucketSec: z.coerce.number().int().min(1).max(86400).default(60)
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) => z.object({ limit: z.coerce.number().int().min(1).max(max).default(fallback) });
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", z2.prettifyError(parsed.error));
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", z3.prettifyError(parsed.error));
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", z3.prettifyError(parsed.error));
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", z4.prettifyError(error));
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 (_request, reply) => {
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 = z5.object({ state: z5.string().min(1).max(200), code: z5.string().min(1).max(4096) }).safeParse(request.query);
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: z6.prettifyError(parsed.error),
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 surfaceOf(url) {
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
- if (surface === "other") return;
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 && pathOf(request.url) === "/api/events") {
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 (surface === "api" && login?.user(authCookie(request, "dc_session"))) {
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 (surface === "v1") {
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
- init.body = JSON.stringify(body);
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 (account) => ({
1551
- launched: await launchLoginTerminal(account.id, { env: options.env })
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-FYPMA55O.js.map
1747
+ //# sourceMappingURL=chunk-KUY3QHGS.js.map