@dmrlzz/davecode 0.3.0 → 0.5.0

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 (120) hide show
  1. package/README.md +5 -4
  2. package/bin/davecode.js +0 -0
  3. package/dist/{ChatApp-FO5SABXB.js → ChatApp-CJBICQGA.js} +289 -137
  4. package/dist/ChatApp-CJBICQGA.js.map +1 -0
  5. package/dist/{RunnerView-DLVR7C22.js → RunnerView-A7JSPUW5.js} +5 -5
  6. package/dist/account-QWDPJWAA.js +23 -0
  7. package/dist/accounts-IQMR72FC.js +37 -0
  8. package/dist/{budget-RBHCEDPP.js → budget-XANOUVWO.js} +6 -6
  9. package/dist/chat-KDDRNC5V.js +359 -0
  10. package/dist/chat-KDDRNC5V.js.map +1 -0
  11. package/dist/{accounts-MTMGYKEP.js → chunk-44AFJL2X.js} +24 -17
  12. package/dist/chunk-44AFJL2X.js.map +1 -0
  13. package/dist/{chunk-BOLFK3BH.js → chunk-5LKOJBUL.js} +2 -2
  14. package/dist/{chunk-23KTE7IK.js → chunk-AZKACMME.js} +2 -2
  15. package/dist/{chunk-PIIJ3RSI.js → chunk-FYPMA55O.js} +1269 -1265
  16. package/dist/chunk-FYPMA55O.js.map +1 -0
  17. package/dist/{chunk-OYEYNDOO.js → chunk-GE22VBCY.js} +3 -3
  18. package/dist/{chunk-C7FDRA3U.js → chunk-HSBJDV3O.js} +660 -139
  19. package/dist/chunk-HSBJDV3O.js.map +1 -0
  20. package/dist/chunk-JLATEHS7.js +20 -0
  21. package/dist/chunk-JLATEHS7.js.map +1 -0
  22. package/dist/{chunk-VVCXGQMY.js → chunk-MC7RIPL7.js} +17 -8
  23. package/dist/chunk-MC7RIPL7.js.map +1 -0
  24. package/dist/{chunk-MSLLH5XP.js → chunk-PGAJIGUF.js} +4 -4
  25. package/dist/{chunk-OXRMGR72.js → chunk-PGPXE6LF.js} +2 -2
  26. package/dist/chunk-QA3O6RA2.js +81 -0
  27. package/dist/chunk-QA3O6RA2.js.map +1 -0
  28. package/dist/chunk-W7GPBEBZ.js +144 -0
  29. package/dist/chunk-W7GPBEBZ.js.map +1 -0
  30. package/dist/{chunk-IVZHKUCD.js → chunk-WQ7MEWDF.js} +3 -3
  31. package/dist/{config-FRMY5OHG.js → config-YTUPIYZT.js} +5 -5
  32. package/dist/dashboard/assets/Accounts-cq8RLMoI.js +1 -0
  33. package/dist/dashboard/assets/Badge-Z4RBdO9j.js +55 -0
  34. package/dist/dashboard/assets/Callout-w8BTYh4k.js +1 -0
  35. package/dist/dashboard/assets/Field-Cmpgg_1z.js +1 -0
  36. package/dist/dashboard/assets/Goals-Bw02to72.js +1 -0
  37. package/dist/dashboard/assets/Library-DK7mlpRb.js +1 -0
  38. package/dist/dashboard/assets/{Markdown-ClRsddnB.js → Markdown-DCZ4Awcc.js} +8 -8
  39. package/dist/dashboard/assets/Panes-_KTf8pbZ.js +8 -0
  40. package/dist/dashboard/assets/Panes-kHJ-D0s7.css +1 -0
  41. package/dist/dashboard/assets/RoutesPage-QV0oPRW9.js +4 -0
  42. package/dist/dashboard/assets/Runner-CkHBLQl0.js +1 -0
  43. package/dist/dashboard/assets/Settings-BLz2gTBR.js +1 -0
  44. package/dist/dashboard/assets/Switch-DPYlLseH.js +1 -0
  45. package/dist/dashboard/assets/Tasks-BiUQSTpt.js +2 -0
  46. package/dist/dashboard/assets/Traffic-BVfBuC70.js +1 -0
  47. package/dist/dashboard/assets/Workspace-CJTgiiU5.js +1 -0
  48. package/dist/dashboard/assets/arrow-up-DjhzZprp.js +1 -0
  49. package/dist/dashboard/assets/cn-BwE4cei0.js +1 -0
  50. package/dist/dashboard/assets/forms-DVIUAxAc.js +1 -0
  51. package/dist/dashboard/assets/index-BDBa5cb0.js +104 -0
  52. package/dist/dashboard/assets/index-BEmBgsbP.css +2 -0
  53. package/dist/dashboard/assets/task-errors-Daqwi0ue.js +1 -0
  54. package/dist/dashboard/assets/trash-BTuDcSaQ.js +1 -0
  55. package/dist/dashboard/favicon.svg +1 -7
  56. package/dist/dashboard/index.html +4 -4
  57. package/dist/{dist-ZPXEVBEC.js → dist-37VQSHHA.js} +24 -2
  58. package/dist/dist-37VQSHHA.js.map +1 -0
  59. package/dist/{doctor-7RUD4D3A.js → doctor-PYUQRRCB.js} +5 -5
  60. package/dist/{goal-JFRNPBSD.js → goal-SXZUDUCL.js} +5 -5
  61. package/dist/index.js +48 -30
  62. package/dist/index.js.map +1 -1
  63. package/dist/{init-NFYNO3A3.js → init-Z2AFQEEP.js} +6 -6
  64. package/dist/{prompts-L37J72YW.js → prompts-TZ7UC42M.js} +9 -5
  65. package/dist/prompts-TZ7UC42M.js.map +1 -0
  66. package/dist/{run-ARUPXFFB.js → run-AOS7L3RT.js} +10 -10
  67. package/dist/runtime.js +18 -0
  68. package/dist/runtime.js.map +1 -0
  69. package/dist/{start-CFPOVIAR.js → start-CEPXKZUE.js} +5 -5
  70. package/dist/{status-E4EACVE2.js → status-WNJ3GGKU.js} +6 -6
  71. package/dist/status-WNJ3GGKU.js.map +1 -0
  72. package/dist/{tasks-ZIK6BVEX.js → tasks-TFUTUMWB.js} +6 -6
  73. package/package.json +21 -15
  74. package/dist/ChatApp-FO5SABXB.js.map +0 -1
  75. package/dist/accounts-MTMGYKEP.js.map +0 -1
  76. package/dist/chat-ZDXX3N6X.js +0 -95
  77. package/dist/chat-ZDXX3N6X.js.map +0 -1
  78. package/dist/chunk-C7FDRA3U.js.map +0 -1
  79. package/dist/chunk-DYQ56FBT.js +0 -47
  80. package/dist/chunk-DYQ56FBT.js.map +0 -1
  81. package/dist/chunk-PIIJ3RSI.js.map +0 -1
  82. package/dist/chunk-VVCXGQMY.js.map +0 -1
  83. package/dist/dashboard/assets/Accounts-BR3ZfVk4.js +0 -1
  84. package/dist/dashboard/assets/Badge-B-qzNRrZ.js +0 -55
  85. package/dist/dashboard/assets/Callout-B9g_wPDi.js +0 -1
  86. package/dist/dashboard/assets/Field-BfabPEcY.js +0 -1
  87. package/dist/dashboard/assets/Goals-BsV-6m94.js +0 -1
  88. package/dist/dashboard/assets/Library-CEA9P1m-.js +0 -1
  89. package/dist/dashboard/assets/Panel-B9tSgX6l.js +0 -1
  90. package/dist/dashboard/assets/RoutesPage-Dh-BJ3ir.js +0 -4
  91. package/dist/dashboard/assets/Runner-C_e9l5l2.js +0 -1
  92. package/dist/dashboard/assets/Settings-C6Yc1Gjg.js +0 -1
  93. package/dist/dashboard/assets/Switch-CUpOJjUT.js +0 -1
  94. package/dist/dashboard/assets/Tasks-CTku0rR3.js +0 -2
  95. package/dist/dashboard/assets/Traffic-CE6wZSMr.js +0 -1
  96. package/dist/dashboard/assets/Workspace-CxFxvkA6.js +0 -1
  97. package/dist/dashboard/assets/arrow-up-DL3CuFOO.js +0 -1
  98. package/dist/dashboard/assets/forms-D6UIYgC5.js +0 -1
  99. package/dist/dashboard/assets/index-1iH716Xy.css +0 -2
  100. package/dist/dashboard/assets/index-BMWr9EKo.js +0 -104
  101. package/dist/dashboard/assets/task-errors-CE4oEr8H.js +0 -1
  102. package/dist/dashboard/assets/trash-CWqeZ7eg.js +0 -1
  103. package/dist/prompts-L37J72YW.js.map +0 -1
  104. /package/dist/{RunnerView-DLVR7C22.js.map → RunnerView-A7JSPUW5.js.map} +0 -0
  105. /package/dist/{dist-ZPXEVBEC.js.map → account-QWDPJWAA.js.map} +0 -0
  106. /package/dist/{status-E4EACVE2.js.map → accounts-IQMR72FC.js.map} +0 -0
  107. /package/dist/{budget-RBHCEDPP.js.map → budget-XANOUVWO.js.map} +0 -0
  108. /package/dist/{chunk-BOLFK3BH.js.map → chunk-5LKOJBUL.js.map} +0 -0
  109. /package/dist/{chunk-23KTE7IK.js.map → chunk-AZKACMME.js.map} +0 -0
  110. /package/dist/{chunk-OYEYNDOO.js.map → chunk-GE22VBCY.js.map} +0 -0
  111. /package/dist/{chunk-MSLLH5XP.js.map → chunk-PGAJIGUF.js.map} +0 -0
  112. /package/dist/{chunk-OXRMGR72.js.map → chunk-PGPXE6LF.js.map} +0 -0
  113. /package/dist/{chunk-IVZHKUCD.js.map → chunk-WQ7MEWDF.js.map} +0 -0
  114. /package/dist/{config-FRMY5OHG.js.map → config-YTUPIYZT.js.map} +0 -0
  115. /package/dist/{doctor-7RUD4D3A.js.map → doctor-PYUQRRCB.js.map} +0 -0
  116. /package/dist/{goal-JFRNPBSD.js.map → goal-SXZUDUCL.js.map} +0 -0
  117. /package/dist/{init-NFYNO3A3.js.map → init-Z2AFQEEP.js.map} +0 -0
  118. /package/dist/{run-ARUPXFFB.js.map → run-AOS7L3RT.js.map} +0 -0
  119. /package/dist/{start-CFPOVIAR.js.map → start-CEPXKZUE.js.map} +0 -0
  120. /package/dist/{tasks-ZIK6BVEX.js.map → tasks-TFUTUMWB.js.map} +0 -0
@@ -1,35 +1,37 @@
1
+ import {
2
+ formatTaskTree,
3
+ summaryLine
4
+ } from "./chunk-AZKACMME.js";
5
+ import {
6
+ brandBanner
7
+ } from "./chunk-JLATEHS7.js";
1
8
  import {
2
9
  Spinner
3
- } from "./chunk-BOLFK3BH.js";
10
+ } from "./chunk-5LKOJBUL.js";
4
11
  import {
5
12
  ThemeProvider,
6
13
  useTheme
7
- } from "./chunk-OXRMGR72.js";
8
- import {
9
- formatTaskTree,
10
- summaryLine
11
- } from "./chunk-23KTE7IK.js";
14
+ } from "./chunk-PGPXE6LF.js";
12
15
  import {
13
16
  emptyUsage,
14
17
  renderAccounts
15
- } from "./chunk-MSLLH5XP.js";
18
+ } from "./chunk-PGAJIGUF.js";
16
19
  import {
17
20
  bar,
18
- formatDuration,
19
21
  formatTokens,
20
22
  levelStyle,
21
23
  padEnd,
22
24
  percent,
23
25
  visibleWidth
24
26
  } from "./chunk-SF5ZEAP4.js";
25
- import "./chunk-DYQ56FBT.js";
26
- import "./chunk-VVCXGQMY.js";
27
- import "./chunk-PIIJ3RSI.js";
27
+ import "./chunk-QA3O6RA2.js";
28
+ import "./chunk-FYPMA55O.js";
28
29
  import "./chunk-7XVXEO7U.js";
29
- import "./chunk-C7FDRA3U.js";
30
+ import "./chunk-HSBJDV3O.js";
31
+ import "./chunk-MC7RIPL7.js";
30
32
 
31
33
  // src/tui/ChatApp.tsx
32
- import { Box as Box4, Static, useApp, useInput, usePaste, useStdout, useWindowSize } from "ink";
34
+ import { Box as Box5, Static, useApp, useInput, usePaste, useStdout, useWindowSize } from "ink";
33
35
  import { useCallback, useEffect, useReducer, useRef, useState } from "react";
34
36
 
35
37
  // src/tui/chat-state.ts
@@ -327,55 +329,95 @@ function InputBox({
327
329
  }
328
330
  );
329
331
  }
330
- function SlashHints({ commands, width }) {
332
+ function SlashHints({
333
+ commands,
334
+ width,
335
+ selected = 0
336
+ }) {
331
337
  const theme = useTheme();
332
338
  if (commands.length === 0) return null;
333
339
  const nameWidth = Math.max(...commands.map((c) => c.name.length + (c.args ? c.args.length + 1 : 0))) + 3;
334
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 2, width, children: commands.map((c, i) => /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
335
- /* @__PURE__ */ jsx(Text, { color: i === 0 ? theme.ink.accent : void 0, children: `/${c.name}${c.args ? ` ${c.args}` : ""}`.padEnd(nameWidth) }),
336
- /* @__PURE__ */ jsx(Text, { dimColor: theme.ink.dim, children: c.description })
337
- ] }, c.name)) });
340
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingX: 1, width, children: commands.map((c, i) => {
341
+ const active = i === selected;
342
+ return /* @__PURE__ */ jsxs(Text, { wrap: "truncate-end", children: [
343
+ /* @__PURE__ */ jsx(Text, { bold: active, dimColor: !active && theme.ink.dim, children: `${active ? theme.glyph.prompt : " "} ${`/${c.name}${c.args ? ` ${c.args}` : ""}`.padEnd(nameWidth)}` }),
344
+ /* @__PURE__ */ jsx(Text, { dimColor: theme.ink.dim, children: c.description })
345
+ ] }, c.name);
346
+ }) });
338
347
  }
339
348
 
340
- // src/tui/components/StatusLine.tsx
349
+ // src/tui/components/Picker.tsx
341
350
  import { Box as Box2, Text as Text2 } from "ink";
342
351
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
352
+ function Picker({
353
+ title,
354
+ options,
355
+ index
356
+ }) {
357
+ const theme = useTheme();
358
+ const numbered = options.length <= 9;
359
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 1, children: [
360
+ /* @__PURE__ */ jsx2(Text2, { bold: true, children: title }),
361
+ options.map((option, i) => {
362
+ const on = i === index;
363
+ return /* @__PURE__ */ jsxs2(Text2, { dimColor: !on && theme.ink.dim, children: [
364
+ on ? "\u203A " : " ",
365
+ numbered ? `${i + 1}. ` : "",
366
+ /* @__PURE__ */ jsx2(Text2, { bold: on, children: option.label }),
367
+ option.hint ? /* @__PURE__ */ jsxs2(Text2, { dimColor: theme.ink.dim, children: [
368
+ " ",
369
+ option.hint
370
+ ] }) : null
371
+ ] }, option.value);
372
+ }),
373
+ /* @__PURE__ */ jsxs2(Text2, { dimColor: theme.ink.dim, children: [
374
+ "\u2191\u2193 select \xB7 enter choose",
375
+ numbered ? " \xB7 1-9" : "",
376
+ " \xB7 esc cancel"
377
+ ] })
378
+ ] });
379
+ }
380
+
381
+ // src/tui/components/StatusLine.tsx
382
+ import { Box as Box3, Text as Text3 } from "ink";
383
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
343
384
  function statusSegments(theme, state, info, width) {
344
385
  const sep = theme.dim(" \xB7 ");
345
- const left2 = [theme.accent(state.model)];
386
+ const left2 = [[9, theme.accent(state.model)]];
346
387
  if (state.lastAccount) {
347
388
  const name = state.lastAccount.label ?? state.lastAccount.id;
348
- left2.push(
389
+ left2.push([
390
+ 8,
349
391
  `${name}${state.lastAccount.provider ? theme.dim(` (${state.lastAccount.provider})`) : ""}`
350
- );
392
+ ]);
393
+ }
394
+ if (state.totalFailovers > 0) {
395
+ left2.push([7, theme.warn(`${state.lastFailovers}/${state.totalFailovers} failovers`)]);
396
+ }
397
+ if (state.tokens.prompt + state.tokens.completion > 0) {
398
+ const arrows = theme.unicode ? ["\u2191", "\u2193"] : ["in", "out"];
399
+ left2.push([
400
+ 5,
401
+ theme.dim(
402
+ `${formatTokens(state.tokens.prompt)}${arrows[0]} ${formatTokens(state.tokens.completion)}${arrows[1]}`
403
+ )
404
+ ]);
351
405
  }
352
- const failovers = state.totalFailovers > 0 ? theme.warn(`${state.lastFailovers}/${state.totalFailovers} failovers`) : theme.dim("0 failovers");
353
- left2.push(failovers);
354
- const arrows = theme.unicode ? ["\u2191", "\u2193"] : ["in", "out"];
355
- left2.push(
356
- theme.dim(
357
- `${formatTokens(state.tokens.prompt)}${arrows[0]} ${formatTokens(state.tokens.completion)}${arrows[1]}`
358
- )
359
- );
360
406
  if (state.quota5h !== void 0) {
361
- left2.push(
407
+ left2.push([
408
+ 6,
362
409
  `${theme.dim("5h")} ${bar(theme, state.quota5h, 6)} ${levelStyle(theme, state.quota5h)(percent(state.quota5h))}`
363
- );
410
+ ]);
364
411
  }
365
- const dot = theme.glyph.dot;
366
- let right2;
412
+ let right2 = "";
367
413
  if (info.notice) right2 = theme.warn(info.notice);
368
- else if (state.connection === "online") {
369
- right2 = `${theme.ok(dot)} ${theme.dim(info.inProcess ? `${info.where}` : "connected")}`;
370
- } else if (state.connection === "connecting") right2 = theme.dim(`${dot} connecting`);
371
- else right2 = theme.error(`${dot} offline`);
372
- const priorities = [0, 1, 2, 4, 3];
373
- let kept = left2.map((_, i) => i);
374
- const render = () => kept.map((i) => left2[i]).join(sep);
414
+ else if (state.connection === "connecting") right2 = theme.dim("connecting");
415
+ else if (state.connection === "offline") right2 = theme.error("offline");
416
+ let kept = left2;
417
+ const render = () => kept.map(([, text]) => text).join(sep);
375
418
  while (kept.length > 1 && visibleWidth(render()) + visibleWidth(right2) + 2 > width) {
376
- const drop = [...priorities].reverse().find((p) => kept.includes(p) && p !== 0);
377
- if (drop === void 0) break;
378
- kept = kept.filter((i) => i !== drop);
419
+ const lowest = Math.min(...kept.map(([p]) => p));
420
+ kept = kept.filter(([p]) => p !== lowest);
379
421
  }
380
422
  return { left: render(), right: right2 };
381
423
  }
@@ -386,15 +428,15 @@ function StatusLine({
386
428
  }) {
387
429
  const theme = useTheme();
388
430
  const { left: left2, right: right2 } = statusSegments(theme, state, info, width - 2);
389
- return /* @__PURE__ */ jsxs2(Box2, { width, justifyContent: "space-between", paddingX: 1, children: [
390
- /* @__PURE__ */ jsx2(Text2, { wrap: "truncate-end", children: left2 }),
391
- /* @__PURE__ */ jsx2(Text2, { wrap: "truncate-start", children: right2 })
431
+ return /* @__PURE__ */ jsxs3(Box3, { width, justifyContent: "space-between", paddingX: 1, children: [
432
+ /* @__PURE__ */ jsx3(Text3, { wrap: "truncate-end", children: left2 }),
433
+ /* @__PURE__ */ jsx3(Text3, { wrap: "truncate-start", children: right2 })
392
434
  ] });
393
435
  }
394
436
 
395
437
  // src/tui/components/Transcript.tsx
396
- import { Box as Box3, Text as Text3 } from "ink";
397
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
438
+ import { Box as Box4, Text as Text4 } from "ink";
439
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
398
440
  function metaLine(meta) {
399
441
  const parts = [];
400
442
  if (meta.accountLabel ?? meta.accountId) {
@@ -409,46 +451,46 @@ function metaLine(meta) {
409
451
  return parts.join(" \xB7 ");
410
452
  }
411
453
  function Marker({ color, glyph }) {
412
- return /* @__PURE__ */ jsx3(Box3, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx3(Text3, { color, children: glyph }) });
454
+ return /* @__PURE__ */ jsx4(Box4, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx4(Text4, { color, children: glyph }) });
413
455
  }
414
456
  function EntryView({ entry }) {
415
457
  const theme = useTheme();
416
458
  switch (entry.kind) {
417
459
  case "banner":
418
- return /* @__PURE__ */ jsx3(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsx3(Text3, { children: entry.text }) });
460
+ return /* @__PURE__ */ jsx4(Box4, { marginBottom: 1, children: /* @__PURE__ */ jsx4(Text4, { children: entry.text }) });
419
461
  case "user":
420
- return /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
421
- /* @__PURE__ */ jsx3(Marker, { color: theme.ink.accent, glyph: theme.glyph.prompt }),
422
- /* @__PURE__ */ jsx3(Text3, { dimColor: theme.ink.dim, children: entry.text })
462
+ return /* @__PURE__ */ jsxs4(Box4, { marginBottom: 1, children: [
463
+ /* @__PURE__ */ jsx4(Marker, { color: theme.ink.accent, glyph: theme.glyph.prompt }),
464
+ /* @__PURE__ */ jsx4(Text4, { dimColor: theme.ink.dim, children: entry.text })
423
465
  ] });
424
466
  case "assistant":
425
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginBottom: 1, children: [
426
- /* @__PURE__ */ jsxs3(Box3, { children: [
427
- /* @__PURE__ */ jsx3(Marker, { color: theme.ink.accent, glyph: theme.glyph.dot }),
428
- /* @__PURE__ */ jsx3(Text3, { children: entry.text || (entry.meta?.cancelled ? "(cancelled before any output)" : "") })
467
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginBottom: 1, children: [
468
+ /* @__PURE__ */ jsxs4(Box4, { children: [
469
+ /* @__PURE__ */ jsx4(Marker, { color: theme.ink.accent, glyph: theme.glyph.dot }),
470
+ /* @__PURE__ */ jsx4(Text4, { children: entry.text || (entry.meta?.cancelled ? "(cancelled before any output)" : "") })
429
471
  ] }),
430
- entry.meta ? /* @__PURE__ */ jsx3(Box3, { paddingLeft: 2, children: /* @__PURE__ */ jsx3(Text3, { dimColor: theme.ink.dim, children: metaLine(entry.meta) }) }) : null
472
+ entry.meta ? /* @__PURE__ */ jsx4(Box4, { paddingLeft: 2, children: /* @__PURE__ */ jsx4(Text4, { dimColor: theme.ink.dim, children: metaLine(entry.meta) }) }) : null
431
473
  ] });
432
474
  case "error":
433
- return /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
434
- /* @__PURE__ */ jsx3(Marker, { color: theme.ink.error, glyph: theme.glyph.fail }),
435
- /* @__PURE__ */ jsx3(Text3, { color: theme.ink.error, children: entry.text })
475
+ return /* @__PURE__ */ jsxs4(Box4, { marginBottom: 1, children: [
476
+ /* @__PURE__ */ jsx4(Marker, { color: theme.ink.error, glyph: theme.glyph.fail }),
477
+ /* @__PURE__ */ jsx4(Text4, { color: theme.ink.error, children: entry.text })
436
478
  ] });
437
479
  default:
438
- return /* @__PURE__ */ jsx3(Box3, { marginBottom: 1, paddingLeft: 2, children: /* @__PURE__ */ jsx3(Text3, { children: entry.text }) });
480
+ return /* @__PURE__ */ jsx4(Box4, { marginBottom: 1, paddingLeft: 2, children: /* @__PURE__ */ jsx4(Text4, { children: entry.text }) });
439
481
  }
440
482
  }
441
483
  function StreamingView({ streaming, now }) {
442
484
  const theme = useTheme();
443
485
  const seconds = Math.max(0, (now - streaming.startedAt) / 1e3).toFixed(0);
444
- return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginBottom: 1, children: [
445
- streaming.text ? /* @__PURE__ */ jsxs3(Box3, { children: [
446
- /* @__PURE__ */ jsx3(Marker, { color: theme.ink.accent, glyph: theme.glyph.dot }),
447
- /* @__PURE__ */ jsx3(Text3, { children: streaming.text })
486
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginBottom: 1, children: [
487
+ streaming.text ? /* @__PURE__ */ jsxs4(Box4, { children: [
488
+ /* @__PURE__ */ jsx4(Marker, { color: theme.ink.accent, glyph: theme.glyph.dot }),
489
+ /* @__PURE__ */ jsx4(Text4, { children: streaming.text })
448
490
  ] }) : null,
449
- /* @__PURE__ */ jsxs3(Box3, { paddingLeft: streaming.text ? 2 : 0, children: [
450
- /* @__PURE__ */ jsx3(Spinner, {}),
451
- /* @__PURE__ */ jsxs3(Text3, { dimColor: theme.ink.dim, children: [
491
+ /* @__PURE__ */ jsxs4(Box4, { paddingLeft: streaming.text ? 2 : 0, children: [
492
+ /* @__PURE__ */ jsx4(Spinner, {}),
493
+ /* @__PURE__ */ jsxs4(Text4, { dimColor: theme.ink.dim, children: [
452
494
  " ",
453
495
  streaming.text ? "streaming" : "thinking",
454
496
  " ",
@@ -462,10 +504,17 @@ function StreamingView({ streaming, now }) {
462
504
  // src/tui/slash.ts
463
505
  var SLASH_COMMANDS = [
464
506
  { name: "model", args: "[id]", description: "show models or switch, e.g. /model davecode/auto" },
507
+ {
508
+ name: "connect",
509
+ description: "connect Claude Code, Codex or Antigravity, or sign in to one again"
510
+ },
465
511
  { name: "route", description: "routes and their failover targets" },
466
512
  { name: "accounts", description: "accounts with 5h quota usage" },
467
513
  { name: "tasks", description: "the project task graph" },
468
- { name: "status", description: "gateway health and runner state" },
514
+ { name: "status", description: "model, agents and whether they are signed in" },
515
+ { name: "login", description: "sign in to your DaveCode account in the browser" },
516
+ { name: "logout", description: "sign out of your DaveCode account" },
517
+ { name: "account", description: "the signed-in DaveCode account" },
469
518
  { name: "clear", description: "clear the transcript and start a new conversation" },
470
519
  { name: "help", description: "commands and keyboard shortcuts", aliases: ["?"] },
471
520
  { name: "exit", description: "quit DaveCode", aliases: ["quit", "q"] }
@@ -487,16 +536,11 @@ function slashSuggestions(input) {
487
536
  (c) => c.name.startsWith(prefix) || c.aliases?.some((a) => a.startsWith(prefix) && prefix)
488
537
  );
489
538
  }
490
- function completeSlash(input) {
491
- const [first] = slashSuggestions(input);
492
- if (!first) return void 0;
493
- return `/${first.name}${first.args ? " " : ""}`;
494
- }
495
539
  var KEY_HINTS = [
496
540
  ["Enter", "send"],
497
541
  ["Shift+Enter, Ctrl+J or \\ Enter", "new line"],
498
542
  ["\u2191 / \u2193", "move between lines, then through history"],
499
- ["Tab", "complete a slash command"],
543
+ ["/", "command menu: \u2191 / \u2193 to choose, Enter to run, Tab to fill, Esc to close"],
500
544
  ["Esc", "cancel the response in flight"],
501
545
  ["Ctrl+U / Ctrl+K / Ctrl+W", "delete to line start / line end / previous word"],
502
546
  ["Ctrl+C twice", "exit"]
@@ -575,49 +619,72 @@ async function tasksText(theme, backend, columns) {
575
619
  ...formatTaskTree(theme, graph, { width: columns })
576
620
  ].join("\n");
577
621
  }
578
- async function statusText(theme, backend) {
622
+ async function statusText(theme, backend, model) {
579
623
  const health = await backend.health();
580
- if (!health) return theme.error(`Gateway at ${backend.url} is not answering.`);
581
- const runner = await backend.runner().catch(() => void 0);
582
- const flags = Object.entries(health.experimental).filter(([, on]) => on).map(([k]) => k);
583
- return [
584
- `${theme.ok(theme.glyph.dot)} ${backend.url}${backend.inProcess ? theme.dim(" (in-process)") : ""} ${theme.dim(`v${health.version} \xB7 up ${formatDuration(health.uptimeSec)}`)}`,
585
- `${theme.dim("runner")} ${runner ? runner.state : "unknown"}${runner?.taskId ? theme.dim(` \xB7 ${runner.taskId}`) : ""}`,
586
- `${theme.dim("experimental")} ${flags.length > 0 ? theme.warn(flags.join(", ")) : "none"}`
587
- ].join("\n");
624
+ if (!health) return theme.error("DaveCode is not answering. Restart it with davecode.");
625
+ const [accounts, runner] = await Promise.all([
626
+ backend.accounts(),
627
+ backend.runner().catch(() => void 0)
628
+ ]);
629
+ const state = (status) => status === "error" ? theme.error("needs sign-in \xB7 /connect") : status === "cooldown" ? theme.warn("cooling down") : status === "disabled" ? theme.dim("off") : theme.ok("ready");
630
+ const lines2 = [`${theme.dim("model ")} ${model}`];
631
+ if (accounts.length === 0) lines2.push(`${theme.dim("agents")} none yet \xB7 /connect`);
632
+ for (const [i, account] of accounts.entries()) {
633
+ lines2.push(
634
+ `${theme.dim(i === 0 ? "agents" : " ")} ${account.label} ${state(account.status)}`
635
+ );
636
+ }
637
+ lines2.push(`${theme.dim("runner")} ${runner ? runner.state : "unknown"}`);
638
+ return lines2.join("\n");
588
639
  }
589
640
 
590
641
  // src/tui/ChatApp.tsx
591
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
592
- var PLACEHOLDER = "Ask anything \xB7 / for commands \xB7 Shift+Enter or Ctrl+J for a new line";
642
+ import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
643
+ var PLACEHOLDER = "Ask anything, or type / for commands";
593
644
  var EXIT_WINDOW_MS = 2e3;
594
645
  function errorText(err) {
595
646
  return err instanceof Error ? err.message : String(err);
596
647
  }
597
- function Chat({ backend, model, version, pollMs = 1e4, now = Date.now }) {
648
+ function Chat({
649
+ backend,
650
+ model,
651
+ version,
652
+ project,
653
+ account,
654
+ connect,
655
+ pollMs = 1e4,
656
+ now = Date.now
657
+ }) {
598
658
  const theme = useTheme();
599
659
  const { exit } = useApp();
600
660
  const { write } = useStdout();
601
661
  const { columns } = useWindowSize();
602
662
  const width = Math.max(20, columns);
663
+ const widthRef = useRef(width);
664
+ widthRef.current = width;
603
665
  const [state, dispatch] = useReducer(chatReducer, model, initialChatState);
604
666
  const [editor, setEditor] = useState(emptyEditor);
605
667
  const [historyIndex, setHistoryIndex] = useState();
606
668
  const [notice, setNotice] = useState();
607
669
  const [clock, setClock] = useState(now());
670
+ const [slashIndex, setSlashIndex] = useState(0);
671
+ const [picker, setPicker] = useState();
608
672
  const abortRef = useRef(void 0);
609
673
  const exitArmedAt = useRef(void 0);
610
674
  const labels = useRef(/* @__PURE__ */ new Map());
611
675
  const stateRef = useRef(state);
612
676
  stateRef.current = state;
613
677
  useEffect(() => {
614
- const where = backend.inProcess ? `${backend.url} (in-process)` : backend.url;
615
678
  dispatch({
616
679
  type: "banner",
617
- text: `${theme.bold(theme.accent("DaveCode"))} ${theme.dim(`v${version}`)}
618
- ${theme.dim(
619
- `model ${model} \xB7 gateway ${where} \xB7 /help for commands`
620
- )}`
680
+ text: brandBanner(
681
+ theme,
682
+ [
683
+ `${theme.bold("DaveCode")} ${theme.dim(`v${version}`)}`,
684
+ ...project ? [theme.dim(project)] : []
685
+ ],
686
+ widthRef.current
687
+ ).join("\n")
621
688
  });
622
689
  let alive = true;
623
690
  const check = async () => {
@@ -635,7 +702,7 @@ ${theme.dim(
635
702
  clearInterval(timer);
636
703
  abortRef.current?.abort();
637
704
  };
638
- }, [backend, model, pollMs, theme, version]);
705
+ }, [backend, pollMs, project, theme, version]);
639
706
  useEffect(() => {
640
707
  if (!state.streaming) return;
641
708
  const timer = setInterval(() => setClock(now()), 250);
@@ -663,11 +730,11 @@ ${theme.dim(
663
730
  [backend]
664
731
  );
665
732
  const send = useCallback(
666
- async (text) => {
667
- dispatch({ type: "user", text });
733
+ async (text2) => {
734
+ dispatch({ type: "user", text: text2 });
668
735
  const conversation = [
669
736
  ...stateRef.current.conversation,
670
- { role: "user", content: text }
737
+ { role: "user", content: text2 }
671
738
  ];
672
739
  const controller = new AbortController();
673
740
  abortRef.current = controller;
@@ -706,14 +773,17 @@ ${theme.dim(
706
773
  } else {
707
774
  const status = err.status;
708
775
  if (status === 0) dispatch({ type: "connection", connection: "offline" });
709
- dispatch({ type: "stream-end", now: now(), error: errorText(err) });
776
+ let text3 = errorText(err);
777
+ if (connect)
778
+ text3 = text3.replace(/Run: davecode accounts login \S+/, "Type /connect to sign in.");
779
+ dispatch({ type: "stream-end", now: now(), error: text3 });
710
780
  }
711
781
  } finally {
712
782
  if (abortRef.current === controller) abortRef.current = void 0;
713
783
  }
714
784
  if (accountId) void refreshQuota(accountId);
715
785
  },
716
- [backend, now, refreshQuota]
786
+ [backend, connect, now, refreshQuota]
717
787
  );
718
788
  const runSlash = useCallback(
719
789
  async (input) => {
@@ -741,17 +811,55 @@ ${theme.dim(
741
811
  write("\x1B[2J\x1B[3J\x1B[H");
742
812
  dispatch({ type: "clear" });
743
813
  break;
744
- case "model":
814
+ case "model": {
815
+ const choose = (id) => {
816
+ dispatch({ type: "set-model", model: id });
817
+ dispatch({ type: "info", text: `Model set to ${theme.accent(id)}` });
818
+ };
745
819
  if (args) {
746
- dispatch({ type: "set-model", model: args });
747
- dispatch({ type: "info", text: `Model set to ${theme.accent(args)}` });
748
- } else {
820
+ choose(args);
821
+ break;
822
+ }
823
+ const ids = (await backend.models()).map((m) => m.id).sort(
824
+ (a, b) => Number(!a.startsWith("davecode/")) - Number(!b.startsWith("davecode/")) || a.localeCompare(b)
825
+ );
826
+ if (ids.length === 0) {
749
827
  dispatch({
750
828
  type: "info",
751
829
  text: await modelsText(theme, backend, stateRef.current.model)
752
830
  });
831
+ break;
753
832
  }
833
+ const current = stateRef.current.model;
834
+ setPicker({
835
+ title: "Choose a model",
836
+ options: ids.map((id) => ({
837
+ value: id,
838
+ label: id,
839
+ ...id === current ? { hint: "(current)" } : {}
840
+ })),
841
+ index: Math.max(0, ids.indexOf(current)),
842
+ pick: choose
843
+ });
754
844
  break;
845
+ }
846
+ case "connect": {
847
+ if (!connect) {
848
+ dispatch({ type: "info", text: "Connect agents with davecode accounts add." });
849
+ break;
850
+ }
851
+ setPicker({
852
+ title: "Connect an agent",
853
+ options: await connect.agents(),
854
+ index: 0,
855
+ pick: (provider) => {
856
+ abortRef.current?.abort();
857
+ connect.choose(provider);
858
+ exit();
859
+ }
860
+ });
861
+ break;
862
+ }
755
863
  case "route":
756
864
  dispatch({ type: "info", text: await routesText(theme, backend) });
757
865
  break;
@@ -765,22 +873,39 @@ ${theme.dim(
765
873
  dispatch({ type: "info", text: await tasksText(theme, backend, width - 4) });
766
874
  break;
767
875
  case "status":
768
- dispatch({ type: "info", text: await statusText(theme, backend) });
876
+ dispatch({
877
+ type: "info",
878
+ text: await statusText(theme, backend, stateRef.current.model)
879
+ });
769
880
  break;
881
+ case "login":
882
+ case "logout":
883
+ case "account": {
884
+ if (!account) {
885
+ dispatch({
886
+ type: "info",
887
+ text: "DaveCode accounts are not available in this build."
888
+ });
889
+ break;
890
+ }
891
+ const text2 = command.name === "login" ? await account.login((note) => dispatch({ type: "info", text: theme.dim(note) })) : command.name === "logout" ? await account.logout() : await account.status();
892
+ dispatch({ type: "info", text: text2 });
893
+ break;
894
+ }
770
895
  }
771
896
  } catch (err) {
772
897
  dispatch({ type: "error", text: `/${command.name} failed: ${errorText(err)}` });
773
898
  }
774
899
  },
775
- [backend, exit, theme, width, write]
900
+ [account, backend, connect, exit, theme, width, write]
776
901
  );
777
902
  const submit = useCallback(() => {
778
- const text = textOf(editor).trim();
779
- if (!text) return;
780
- if (parseSlash(text).kind !== "none") {
903
+ const text2 = textOf(editor).trim();
904
+ if (!text2) return;
905
+ if (parseSlash(text2).kind !== "none") {
781
906
  setEditor(emptyEditor);
782
907
  setHistoryIndex(void 0);
783
- void runSlash(text);
908
+ void runSlash(text2);
784
909
  return;
785
910
  }
786
911
  if (stateRef.current.streaming) {
@@ -789,7 +914,7 @@ ${theme.dim(
789
914
  }
790
915
  setEditor(emptyEditor);
791
916
  setHistoryIndex(void 0);
792
- void send(text);
917
+ void send(text2);
793
918
  }, [editor, runSlash, send]);
794
919
  const recall = (direction) => {
795
920
  const { history } = stateRef.current;
@@ -814,6 +939,37 @@ ${theme.dim(
814
939
  return;
815
940
  }
816
941
  exitArmedAt.current = void 0;
942
+ if (picker) {
943
+ const count = picker.options.length;
944
+ const move = (index) => setPicker({ ...picker, index });
945
+ if (key.escape) return setPicker(void 0);
946
+ if (key.upArrow) return move((picker.index - 1 + count) % count);
947
+ if (key.downArrow) return move((picker.index + 1) % count);
948
+ const digit = count <= 9 && /^[1-9]$/.test(input) ? Number(input) - 1 : void 0;
949
+ if (key.return || digit !== void 0 && digit < count) {
950
+ const option = picker.options[digit ?? picker.index];
951
+ setPicker(void 0);
952
+ if (option) picker.pick(option.value);
953
+ }
954
+ return;
955
+ }
956
+ const menu = slashSuggestions(textOf(editor));
957
+ if (menu.length > 0) {
958
+ const selected = menu[Math.min(slashIndex, menu.length - 1)];
959
+ if (key.upArrow) return setSlashIndex((i) => (i - 1 + menu.length) % menu.length);
960
+ if (key.downArrow) return setSlashIndex((i) => (i + 1) % menu.length);
961
+ if (key.escape) return setEditor(emptyEditor);
962
+ if (key.tab) {
963
+ setEditor(fromText(`/${selected.name}${selected.args ? " " : ""}`));
964
+ return;
965
+ }
966
+ if (key.return && !key.shift && !key.meta) {
967
+ setEditor(emptyEditor);
968
+ setHistoryIndex(void 0);
969
+ void runSlash(`/${selected.name}`);
970
+ return;
971
+ }
972
+ }
817
973
  if (key.escape) {
818
974
  if (stateRef.current.streaming) abortRef.current?.abort();
819
975
  return;
@@ -828,11 +984,7 @@ ${theme.dim(
828
984
  else submit();
829
985
  return;
830
986
  }
831
- if (key.tab) {
832
- const completed = completeSlash(textOf(editor));
833
- if (completed) setEditor(fromText(completed));
834
- return;
835
- }
987
+ if (key.tab) return;
836
988
  if (key.upArrow) {
837
989
  const moved = up(editor);
838
990
  if (moved) setEditor(moved);
@@ -861,33 +1013,33 @@ ${theme.dim(
861
1013
  if (key.ctrl || key.meta || !input) return;
862
1014
  setEditor((e) => insert(e, input));
863
1015
  });
864
- usePaste((text) => {
865
- setEditor((e) => insert(e, text));
1016
+ usePaste((text2) => {
1017
+ setEditor((e) => insert(e, text2));
866
1018
  });
867
- const suggestions = slashSuggestions(textOf(editor));
868
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", width, children: [
869
- /* @__PURE__ */ jsx4(Static, { items: state.entries, children: (entry) => /* @__PURE__ */ jsx4(EntryView, { entry }, entry.id) }, state.epoch),
870
- state.streaming ? /* @__PURE__ */ jsx4(StreamingView, { streaming: state.streaming, now: clock }) : null,
871
- /* @__PURE__ */ jsx4(InputBox, { editor, width, placeholder: PLACEHOLDER }),
872
- /* @__PURE__ */ jsx4(SlashHints, { commands: suggestions, width }),
873
- /* @__PURE__ */ jsx4(
874
- StatusLine,
875
- {
876
- state,
877
- width,
878
- info: {
879
- where: backend.inProcess ? `in-process ${new URL(backend.url).port}` : backend.url,
880
- inProcess: backend.inProcess,
881
- ...notice ? { notice } : {}
1019
+ const text = textOf(editor);
1020
+ const suggestions = slashSuggestions(text);
1021
+ useEffect(() => setSlashIndex(0), [text]);
1022
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", width, children: [
1023
+ /* @__PURE__ */ jsx5(Static, { items: state.entries, children: (entry) => /* @__PURE__ */ jsx5(EntryView, { entry }, entry.id) }, state.epoch),
1024
+ state.streaming ? /* @__PURE__ */ jsx5(StreamingView, { streaming: state.streaming, now: clock }) : null,
1025
+ picker ? /* @__PURE__ */ jsx5(Picker, { title: picker.title, options: picker.options, index: picker.index }) : /* @__PURE__ */ jsxs5(Fragment, { children: [
1026
+ /* @__PURE__ */ jsx5(InputBox, { editor, width, placeholder: PLACEHOLDER }),
1027
+ /* @__PURE__ */ jsx5(
1028
+ SlashHints,
1029
+ {
1030
+ commands: suggestions,
1031
+ width,
1032
+ selected: Math.min(slashIndex, Math.max(0, suggestions.length - 1))
882
1033
  }
883
- }
884
- )
1034
+ )
1035
+ ] }),
1036
+ !picker && suggestions.length === 0 ? /* @__PURE__ */ jsx5(StatusLine, { state, width, info: notice ? { notice } : {} }) : null
885
1037
  ] });
886
1038
  }
887
1039
  function ChatApp(props) {
888
- return /* @__PURE__ */ jsx4(ThemeProvider, { theme: props.theme, children: /* @__PURE__ */ jsx4(Chat, { ...props }) });
1040
+ return /* @__PURE__ */ jsx5(ThemeProvider, { theme: props.theme, children: /* @__PURE__ */ jsx5(Chat, { ...props }) });
889
1041
  }
890
1042
  export {
891
1043
  ChatApp
892
1044
  };
893
- //# sourceMappingURL=ChatApp-FO5SABXB.js.map
1045
+ //# sourceMappingURL=ChatApp-CJBICQGA.js.map