darkfoo-code 0.2.3 → 0.2.5

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 (2) hide show
  1. package/dist/main.js +150 -474
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -1926,133 +1926,22 @@ function App({ model, systemPromptOverride, children }) {
1926
1926
  }
1927
1927
 
1928
1928
  // src/repl.tsx
1929
- import { useState as useState3, useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2 } from "react";
1929
+ import { useState as useState2, useCallback as useCallback2, useEffect, useRef } from "react";
1930
1930
  import { Box as Box7, Text as Text7, useApp, useInput as useInput2 } from "ink";
1931
- import Spinner2 from "ink-spinner";
1932
1931
  import { nanoid as nanoid6 } from "nanoid";
1933
1932
 
1934
1933
  // src/components/Banner.tsx
1935
1934
  init_theme();
1935
+ import { memo as memo2 } from "react";
1936
1936
  import { Box as Box2, Text as Text2 } from "ink";
1937
1937
 
1938
1938
  // src/components/Fox.tsx
1939
1939
  init_theme();
1940
- import { useState, useEffect, useRef } from "react";
1940
+ import { memo } from "react";
1941
1941
  import { Box, Text } from "ink";
1942
-
1943
- // src/fox-state.ts
1944
- var DEFAULT_STATS = {
1945
- name: "DarkFox",
1946
- happiness: 70,
1947
- hunger: 80,
1948
- energy: 90,
1949
- timesPetted: 0,
1950
- timesFed: 0,
1951
- createdAt: Date.now()
1952
- };
1953
- var stats = { ...DEFAULT_STATS };
1954
- var lastDecayTime = Date.now();
1955
- function getFoxStats() {
1956
- decay();
1957
- return { ...stats };
1958
- }
1959
- function setFoxName(name) {
1960
- stats.name = name;
1961
- }
1962
- function petFox() {
1963
- decay();
1964
- stats.happiness = Math.min(100, stats.happiness + 15);
1965
- stats.timesPetted++;
1966
- const reactions = [
1967
- `${stats.name} nuzzles your hand.`,
1968
- `${stats.name} purrs softly.`,
1969
- `${stats.name}'s tail wags happily.`,
1970
- `${stats.name} leans into the pets.`,
1971
- `${stats.name} rolls over for belly rubs.`,
1972
- `${stats.name} makes a happy chirping sound.`,
1973
- `${stats.name} bumps your hand with their nose.`
1974
- ];
1975
- if (stats.happiness >= 95) {
1976
- return `${stats.name} is absolutely overjoyed! Maximum floof achieved.`;
1977
- }
1978
- return reactions[stats.timesPetted % reactions.length];
1979
- }
1980
- function feedFox() {
1981
- decay();
1982
- stats.hunger = Math.min(100, stats.hunger + 25);
1983
- stats.happiness = Math.min(100, stats.happiness + 5);
1984
- stats.timesFed++;
1985
- const foods = [
1986
- "a small cookie",
1987
- "some berries",
1988
- "a piece of fish",
1989
- "a tiny sandwich",
1990
- "some trail mix",
1991
- "a warm dumpling",
1992
- "a bit of cheese"
1993
- ];
1994
- const food = foods[stats.timesFed % foods.length];
1995
- if (stats.hunger >= 95) {
1996
- return `${stats.name} nibbles ${food} contentedly. Completely stuffed!`;
1997
- }
1998
- return `${stats.name} happily munches on ${food}.`;
1999
- }
2000
- function restFox() {
2001
- decay();
2002
- stats.energy = Math.min(100, stats.energy + 30);
2003
- stats.happiness = Math.min(100, stats.happiness + 5);
2004
- return `${stats.name} curls up for a quick nap... Energy restored!`;
2005
- }
2006
- function getFoxComment() {
2007
- decay();
2008
- if (stats.hunger < 20) {
2009
- const hungry = [
2010
- `${stats.name} looks at you hopefully...`,
2011
- `${stats.name}'s stomach growls.`,
2012
- `${stats.name} sniffs around for food.`
2013
- ];
2014
- return hungry[Math.floor(Math.random() * hungry.length)];
2015
- }
2016
- if (stats.energy < 20) {
2017
- const tired = [
2018
- `${stats.name} yawns widely.`,
2019
- `${stats.name}'s eyelids are drooping.`,
2020
- `${stats.name} stretches and looks sleepy.`
2021
- ];
2022
- return tired[Math.floor(Math.random() * tired.length)];
2023
- }
2024
- if (stats.happiness < 30) {
2025
- return `${stats.name} looks a bit lonely. Try /pet`;
2026
- }
2027
- if (Math.random() < 0.15 && stats.happiness > 60) {
2028
- const happy = [
2029
- `${stats.name} watches your code intently.`,
2030
- `${stats.name} tilts their head curiously.`,
2031
- `${stats.name} flicks an ear.`,
2032
- null,
2033
- null,
2034
- null
2035
- ];
2036
- return happy[Math.floor(Math.random() * happy.length)] ?? null;
2037
- }
2038
- return null;
2039
- }
2040
- function decay() {
2041
- const now = Date.now();
2042
- const elapsed = (now - lastDecayTime) / 6e4;
2043
- if (elapsed < 1) return;
2044
- lastDecayTime = now;
2045
- const minutes = Math.floor(elapsed);
2046
- stats.hunger = Math.max(0, stats.hunger - minutes * 1.5);
2047
- stats.energy = Math.max(0, stats.energy - minutes * 0.5);
2048
- if (stats.hunger < 30) stats.happiness = Math.max(0, stats.happiness - minutes * 1);
2049
- if (stats.energy < 20) stats.happiness = Math.max(0, stats.happiness - minutes * 0.5);
2050
- }
2051
-
2052
- // src/components/Fox.tsx
2053
1942
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
2054
- var IDLE = [
2055
- [
1943
+ var FRAMES = {
1944
+ idle: [
2056
1945
  " /\\_/\\ ",
2057
1946
  " ( o.o ) ",
2058
1947
  " > ^ < ",
@@ -2060,133 +1949,23 @@ var IDLE = [
2060
1949
  " (_| |_)",
2061
1950
  " ~ "
2062
1951
  ],
2063
- [
2064
- " /\\_/\\ ",
2065
- " ( o.o ) ",
2066
- " > ^ < ",
2067
- " /| |\\ ",
2068
- " (_| |_)",
2069
- " ~ "
2070
- ],
2071
- [
2072
- " /\\_/\\ ",
2073
- " ( o.o ) ",
2074
- " > < ",
2075
- " /| |\\ ",
2076
- " (_| |_)",
2077
- " ~ "
2078
- ],
2079
- [
2080
- " /\\_/\\ ",
2081
- " ( o.o ) ",
2082
- " > ^ < ",
2083
- " /| |\\ ",
2084
- " (_| |_)",
2085
- " ~ "
2086
- ],
2087
- [
2088
- " /\\_/\\ ",
2089
- " ( o.o ) ",
2090
- " > ^ < ",
2091
- " /| |\\ ",
2092
- " (_| |_)",
2093
- " ~ "
2094
- ],
2095
- [
2096
- " /\\_/\\ ",
2097
- " ( o.o ) ",
2098
- " > < ",
2099
- " /| |\\ ",
2100
- " (_| |_)",
2101
- " ~ "
2102
- ]
2103
- ];
2104
- var THINKING = [
2105
- [
2106
- " /\\_/\\ ",
2107
- " ( o.o ) ",
2108
- " > ^ < ",
2109
- " | | ",
2110
- " |___| ",
2111
- " . "
2112
- ],
2113
- [
1952
+ thinking: [
2114
1953
  " /\\_/\\ ",
2115
1954
  " ( o.- ) ",
2116
1955
  " > ^ < ",
2117
1956
  " | | ",
2118
1957
  " |___| ",
2119
- " . . "
2120
- ],
2121
- [
2122
- " /\\_/\\ ",
2123
- " ( -.o ) ",
2124
- " > ^ < ",
2125
- " | | ",
2126
- " |___| ",
2127
- " . . . "
2128
- ],
2129
- [
2130
- " /\\_/\\ ",
2131
- " ( o.o ) ",
2132
- " > ^ < ",
2133
- " | | ",
2134
- " |___| ",
2135
- " . . "
2136
- ],
2137
- [
2138
- " /\\_/\\ ",
2139
- " ( o.. ) ",
2140
- " > ^ < ",
2141
- " | | ",
2142
- " |___| ",
2143
- " . "
2144
- ],
2145
- [
2146
- " /\\_/\\ ",
2147
- " ( ..o ) ",
2148
- " > ^ < ",
2149
- " | | ",
2150
- " |___| ",
2151
1958
  " . . . "
2152
- ]
2153
- ];
2154
- var WORKING = [
2155
- [
2156
- " /\\_/\\ ",
2157
- " ( >.< ) ",
2158
- " > ^ < ",
2159
- " /| |\\ ",
2160
- " (_| |_)",
2161
- " ~\\ "
2162
1959
  ],
2163
- [
1960
+ working: [
2164
1961
  " /\\_/\\ ",
2165
1962
  " ( >.< ) ",
2166
1963
  " > ^ < ",
2167
1964
  " /| |\\ ",
2168
1965
  " (_| |_)",
2169
- " /~ "
2170
- ],
2171
- [
2172
- " /\\_/\\ ",
2173
- " ( >.> ) ",
2174
- " > ^ < ",
2175
- " /| |\\ ",
2176
- " (_| |_)",
2177
1966
  " ~\\ "
2178
1967
  ],
2179
- [
2180
- " /\\_/\\ ",
2181
- " ( <.< ) ",
2182
- " > ^ < ",
2183
- " /| |\\ ",
2184
- " (_| |_)",
2185
- " /~ "
2186
- ]
2187
- ];
2188
- var SUCCESS = [
2189
- [
1968
+ success: [
2190
1969
  " /\\_/\\ ",
2191
1970
  " ( ^.^ ) ",
2192
1971
  " > w < ",
@@ -2194,59 +1973,15 @@ var SUCCESS = [
2194
1973
  " (_| |_)",
2195
1974
  " \\~/ * "
2196
1975
  ],
2197
- [
2198
- " ",
2199
- " /\\_/\\ ",
2200
- " ( ^.^ ) ",
2201
- " > w < ",
2202
- " /| * |\\ ",
2203
- " \\~/ "
2204
- ],
2205
- [
2206
- " /\\_/\\ ",
2207
- " ( ^.^ ) ",
2208
- " > w < ",
2209
- " /| |\\ ",
2210
- " (_| |_)",
2211
- " * \\~/ "
2212
- ]
2213
- ];
2214
- var ERROR = [
2215
- [
1976
+ error: [
2216
1977
  " /\\_/\\ ",
2217
1978
  " ( ;.; ) ",
2218
1979
  " > n < ",
2219
1980
  " | | ",
2220
1981
  " |___| ",
2221
- " . "
2222
- ],
2223
- [
2224
- " /\\_/\\ ",
2225
- " ( ;_; ) ",
2226
- " > n < ",
2227
- " | | ",
2228
- " |___| ",
2229
1982
  " "
2230
- ]
2231
- ];
2232
- var GREETING = [
2233
- [
2234
- " /\\_/\\ ",
2235
- " ( ^.^ )/",
2236
- " > w < ",
2237
- " /| | ",
2238
- " (_| |) ",
2239
- " \\~/ "
2240
1983
  ],
2241
- [
2242
- " /\\_/\\ ",
2243
- " ( ^.^ ) ",
2244
- " > w <| ",
2245
- " /| | ",
2246
- " (_| |) ",
2247
- " \\~/ "
2248
- ],
2249
- [
1984
+ greeting: [
2250
1985
  " /\\_/\\ ",
2251
1986
  " ( ^.^ )/",
2252
1987
  " > w < ",
@@ -2254,33 +1989,7 @@ var GREETING = [
2254
1989
  " (_| |) ",
2255
1990
  " \\~/ "
2256
1991
  ],
2257
- [
2258
- " /\\_/\\ ",
2259
- " ( ^.^ ) ",
2260
- " > w < ",
2261
- " /| |\\ ",
2262
- " (_| |_)",
2263
- " \\~/ "
2264
- ]
2265
- ];
2266
- var PET = [
2267
- [
2268
- " /\\_/\\ ",
2269
- " ( ^.^ ) ",
2270
- " > w < ",
2271
- " /| |\\ ",
2272
- " (_| ~ |_)",
2273
- " \\~/ "
2274
- ],
2275
- [
2276
- " /\\_/\\ ",
2277
- " ( >.< ) ",
2278
- " > w < ",
2279
- " /| ~ |\\ ",
2280
- " (_| |_)",
2281
- " \\~/ "
2282
- ],
2283
- [
1992
+ pet: [
2284
1993
  " /\\_/\\ ",
2285
1994
  " ( ^w^ ) ",
2286
1995
  " > ~ < ",
@@ -2288,25 +1997,7 @@ var PET = [
2288
1997
  " (_| |_)",
2289
1998
  " \\~/ * "
2290
1999
  ],
2291
- [
2292
- " /\\_/\\ ",
2293
- " ( ^.^ ) ",
2294
- " > w < ",
2295
- " /| |\\ ",
2296
- " (_| |_)",
2297
- " * \\~/ "
2298
- ]
2299
- ];
2300
- var EATING = [
2301
- [
2302
- " /\\_/\\ ",
2303
- " ( o.o )~",
2304
- " > ^ < o",
2305
- " /| |\\ ",
2306
- " (_| |_)",
2307
- " \\~/ "
2308
- ],
2309
- [
2000
+ eating: [
2310
2001
  " /\\_/\\ ",
2311
2002
  " ( >o< ) ",
2312
2003
  " > ~ < ",
@@ -2314,78 +2005,14 @@ var EATING = [
2314
2005
  " (_| |_)",
2315
2006
  " \\~/ "
2316
2007
  ],
2317
- [
2318
- " /\\_/\\ ",
2319
- " ( ^.^ ) ",
2320
- " > o < ",
2321
- " /| |\\ ",
2322
- " (_| |_)",
2323
- " \\~/ "
2324
- ],
2325
- [
2326
- " /\\_/\\ ",
2327
- " ( ^w^ ) ",
2328
- " > ~ < ",
2329
- " /| |\\ ",
2330
- " (_| |_)",
2331
- " \\~/ "
2332
- ]
2333
- ];
2334
- var SLEEPING = [
2335
- [
2336
- " /\\_/\\ ",
2337
- " ( -.- ) ",
2338
- " > ~ < ",
2339
- " | | ",
2340
- " |___| ",
2341
- " z "
2342
- ],
2343
- [
2344
- " /\\_/\\ ",
2345
- " ( -.- ) ",
2346
- " > ~ < ",
2347
- " | | ",
2348
- " |___| ",
2349
- " z z "
2350
- ],
2351
- [
2008
+ sleeping: [
2352
2009
  " /\\_/\\ ",
2353
2010
  " ( -.- ) ",
2354
2011
  " > ~ < ",
2355
2012
  " | | ",
2356
2013
  " |___| ",
2357
2014
  " z z z "
2358
- ],
2359
- [
2360
- " /\\_/\\ ",
2361
- " ( -.- ) ",
2362
- " > ~ < ",
2363
- " | | ",
2364
- " |___| ",
2365
- " z z "
2366
2015
  ]
2367
- ];
2368
- var FRAME_SETS = {
2369
- idle: IDLE,
2370
- thinking: THINKING,
2371
- working: WORKING,
2372
- success: SUCCESS,
2373
- error: ERROR,
2374
- greeting: GREETING,
2375
- pet: PET,
2376
- eating: EATING,
2377
- sleeping: SLEEPING
2378
- };
2379
- var FRAME_SPEEDS = {
2380
- idle: 500,
2381
- thinking: 350,
2382
- working: 200,
2383
- success: 400,
2384
- error: 800,
2385
- greeting: 350,
2386
- pet: 300,
2387
- eating: 350,
2388
- sleeping: 900
2389
2016
  };
2390
2017
  var BODY_COLORS = {
2391
2018
  idle: "#5eead4",
@@ -2409,46 +2036,12 @@ var FACE_COLORS = {
2409
2036
  eating: "#fbbf24",
2410
2037
  sleeping: "#7e8ea6"
2411
2038
  };
2412
- function Fox({ mood = "idle" }) {
2413
- const [frameIdx, setFrameIdx] = useState(0);
2414
- const [bubble, setBubble] = useState(null);
2415
- const frames = FRAME_SETS[mood];
2416
- const speed = FRAME_SPEEDS[mood];
2417
- const bubbleTimer = useRef(null);
2418
- useEffect(() => {
2419
- setFrameIdx(0);
2420
- const interval = setInterval(() => {
2421
- setFrameIdx((prev) => (prev + 1) % frames.length);
2422
- }, speed);
2423
- return () => clearInterval(interval);
2424
- }, [mood, frames.length, speed]);
2425
- useEffect(() => {
2426
- if (mood !== "idle") {
2427
- setBubble(null);
2428
- return;
2429
- }
2430
- const check = () => {
2431
- const comment = getFoxComment();
2432
- if (comment) {
2433
- setBubble(comment);
2434
- if (bubbleTimer.current) clearTimeout(bubbleTimer.current);
2435
- bubbleTimer.current = setTimeout(() => setBubble(null), 6e3);
2436
- }
2437
- };
2438
- const interval = setInterval(check, 15e3);
2439
- return () => {
2440
- clearInterval(interval);
2441
- if (bubbleTimer.current) clearTimeout(bubbleTimer.current);
2442
- };
2443
- }, [mood]);
2444
- const frame = frames[frameIdx] ?? frames[0];
2039
+ var Fox = memo(function Fox2({ mood = "idle" }) {
2040
+ const frame = FRAMES[mood];
2445
2041
  const bodyColor = BODY_COLORS[mood];
2446
2042
  const faceColor = FACE_COLORS[mood];
2447
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
2448
- bubble ? /* @__PURE__ */ jsx2(FoxBubble, { text: bubble }) : null,
2449
- frame.map((line, i) => /* @__PURE__ */ jsx2(Text, { color: i <= 1 ? faceColor : bodyColor, children: line }, i))
2450
- ] });
2451
- }
2043
+ return /* @__PURE__ */ jsx2(Box, { flexDirection: "column", children: frame.map((line, i) => /* @__PURE__ */ jsx2(Text, { color: i <= 1 ? faceColor : bodyColor, children: line }, i)) });
2044
+ });
2452
2045
  function FoxBubble({ text }) {
2453
2046
  if (!text) return null;
2454
2047
  const maxW = 28;
@@ -2495,7 +2088,7 @@ function gradientBar(width) {
2495
2088
  color: GRADIENT[Math.round(i / (width - 1) * (GRADIENT.length - 1))]
2496
2089
  }));
2497
2090
  }
2498
- function Banner({ model, cwd, providerName, providerOnline }) {
2091
+ var Banner = memo2(function Banner2({ model, cwd, providerName, providerOnline }) {
2499
2092
  const bar = gradientBar(60);
2500
2093
  const statusTag = providerOnline ? "[connected]" : "[offline]";
2501
2094
  const statusColor = providerOnline ? theme.green ?? "#4ade80" : theme.pink ?? "#f472b6";
@@ -2534,11 +2127,12 @@ function Banner({ model, cwd, providerName, providerOnline }) {
2534
2127
  bar.map((d, i) => /* @__PURE__ */ jsx3(Text2, { color: d.color, children: d.char }, i))
2535
2128
  ] }) })
2536
2129
  ] });
2537
- }
2130
+ });
2538
2131
 
2539
2132
  // src/components/Messages.tsx
2540
2133
  init_theme();
2541
2134
  init_format();
2135
+ import { memo as memo3 } from "react";
2542
2136
  import { Box as Box3, Text as Text3 } from "ink";
2543
2137
 
2544
2138
  // src/utils/markdown.ts
@@ -2604,9 +2198,9 @@ function renderInline(text) {
2604
2198
 
2605
2199
  // src/components/Messages.tsx
2606
2200
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
2607
- function Messages({ messages }) {
2201
+ var Messages = memo3(function Messages2({ messages }) {
2608
2202
  return /* @__PURE__ */ jsx4(Box3, { flexDirection: "column", children: messages.map((msg) => /* @__PURE__ */ jsx4(MessageRow, { message: msg }, msg.id)) });
2609
- }
2203
+ });
2610
2204
  function MessageRow({ message }) {
2611
2205
  switch (message.role) {
2612
2206
  case "user":
@@ -2641,11 +2235,10 @@ function MessageRow({ message }) {
2641
2235
  init_theme();
2642
2236
  init_format();
2643
2237
  import { Box as Box4, Text as Text4 } from "ink";
2644
- import Spinner from "ink-spinner";
2645
2238
  import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
2646
2239
  function ActiveToolCall({ toolName, args }) {
2647
2240
  return /* @__PURE__ */ jsxs4(Box4, { marginLeft: 2, children: [
2648
- /* @__PURE__ */ jsx5(Text4, { color: theme.cyan, children: /* @__PURE__ */ jsx5(Spinner, { type: "dots" }) }),
2241
+ /* @__PURE__ */ jsx5(Text4, { color: theme.cyan, children: "..." }),
2649
2242
  /* @__PURE__ */ jsxs4(Text4, { bold: true, color: theme.yellow, children: [
2650
2243
  " ",
2651
2244
  toolName
@@ -2691,6 +2284,7 @@ function formatToolArgs(args) {
2691
2284
  // src/components/StatusLine.tsx
2692
2285
  init_theme();
2693
2286
  init_state();
2287
+ import { memo as memo4 } from "react";
2694
2288
  import { Box as Box5, Text as Text5 } from "ink";
2695
2289
  import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
2696
2290
  function getContextLimit(model) {
@@ -2703,7 +2297,7 @@ function getContextLimit(model) {
2703
2297
  if (lower.includes("deepseek")) return 32768;
2704
2298
  return 8192;
2705
2299
  }
2706
- function StatusLine({ model, messageCount, tokenEstimate, isStreaming }) {
2300
+ var StatusLine = memo4(function StatusLine2({ model, messageCount, tokenEstimate, isStreaming }) {
2707
2301
  const state2 = getAppState();
2708
2302
  const contextLimit = getContextLimit(model);
2709
2303
  const usage = Math.min(tokenEstimate / contextLimit, 1);
@@ -2748,11 +2342,11 @@ function StatusLine({ model, messageCount, tokenEstimate, isStreaming }) {
2748
2342
  "\u2500".repeat(2)
2749
2343
  ] })
2750
2344
  ] });
2751
- }
2345
+ });
2752
2346
 
2753
2347
  // src/components/UserInput.tsx
2754
2348
  init_theme();
2755
- import { useState as useState2, useCallback } from "react";
2349
+ import { useState, useCallback, memo as memo5 } from "react";
2756
2350
  import { Box as Box6, Text as Text6, useInput } from "ink";
2757
2351
  import TextInput from "ink-text-input";
2758
2352
 
@@ -3686,6 +3280,81 @@ var providerCommand = {
3686
3280
  }
3687
3281
  };
3688
3282
 
3283
+ // src/fox-state.ts
3284
+ var DEFAULT_STATS = {
3285
+ name: "DarkFox",
3286
+ happiness: 70,
3287
+ hunger: 80,
3288
+ energy: 90,
3289
+ timesPetted: 0,
3290
+ timesFed: 0,
3291
+ createdAt: Date.now()
3292
+ };
3293
+ var stats = { ...DEFAULT_STATS };
3294
+ var lastDecayTime = Date.now();
3295
+ function getFoxStats() {
3296
+ decay();
3297
+ return { ...stats };
3298
+ }
3299
+ function setFoxName(name) {
3300
+ stats.name = name;
3301
+ }
3302
+ function petFox() {
3303
+ decay();
3304
+ stats.happiness = Math.min(100, stats.happiness + 15);
3305
+ stats.timesPetted++;
3306
+ const reactions = [
3307
+ `${stats.name} nuzzles your hand.`,
3308
+ `${stats.name} purrs softly.`,
3309
+ `${stats.name}'s tail wags happily.`,
3310
+ `${stats.name} leans into the pets.`,
3311
+ `${stats.name} rolls over for belly rubs.`,
3312
+ `${stats.name} makes a happy chirping sound.`,
3313
+ `${stats.name} bumps your hand with their nose.`
3314
+ ];
3315
+ if (stats.happiness >= 95) {
3316
+ return `${stats.name} is absolutely overjoyed! Maximum floof achieved.`;
3317
+ }
3318
+ return reactions[stats.timesPetted % reactions.length];
3319
+ }
3320
+ function feedFox() {
3321
+ decay();
3322
+ stats.hunger = Math.min(100, stats.hunger + 25);
3323
+ stats.happiness = Math.min(100, stats.happiness + 5);
3324
+ stats.timesFed++;
3325
+ const foods = [
3326
+ "a small cookie",
3327
+ "some berries",
3328
+ "a piece of fish",
3329
+ "a tiny sandwich",
3330
+ "some trail mix",
3331
+ "a warm dumpling",
3332
+ "a bit of cheese"
3333
+ ];
3334
+ const food = foods[stats.timesFed % foods.length];
3335
+ if (stats.hunger >= 95) {
3336
+ return `${stats.name} nibbles ${food} contentedly. Completely stuffed!`;
3337
+ }
3338
+ return `${stats.name} happily munches on ${food}.`;
3339
+ }
3340
+ function restFox() {
3341
+ decay();
3342
+ stats.energy = Math.min(100, stats.energy + 30);
3343
+ stats.happiness = Math.min(100, stats.happiness + 5);
3344
+ return `${stats.name} curls up for a quick nap... Energy restored!`;
3345
+ }
3346
+ function decay() {
3347
+ const now = Date.now();
3348
+ const elapsed = (now - lastDecayTime) / 6e4;
3349
+ if (elapsed < 1) return;
3350
+ lastDecayTime = now;
3351
+ const minutes = Math.floor(elapsed);
3352
+ stats.hunger = Math.max(0, stats.hunger - minutes * 1.5);
3353
+ stats.energy = Math.max(0, stats.energy - minutes * 0.5);
3354
+ if (stats.hunger < 30) stats.happiness = Math.max(0, stats.happiness - minutes * 1);
3355
+ if (stats.energy < 20) stats.happiness = Math.max(0, stats.happiness - minutes * 0.5);
3356
+ }
3357
+
3689
3358
  // src/commands/fox.ts
3690
3359
  var petCommand = {
3691
3360
  name: "pet",
@@ -3814,9 +3483,9 @@ function getCommandNames() {
3814
3483
 
3815
3484
  // src/components/UserInput.tsx
3816
3485
  import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
3817
- function UserInput({ value, onChange, onSubmit, disabled, history }) {
3818
- const [historyIdx, setHistoryIdx] = useState2(-1);
3819
- const [suggestion, setSuggestion] = useState2("");
3486
+ var UserInput = memo5(function UserInput2({ value, onChange, onSubmit, disabled, history }) {
3487
+ const [historyIdx, setHistoryIdx] = useState(-1);
3488
+ const [suggestion, setSuggestion] = useState("");
3820
3489
  useInput((_input, key) => {
3821
3490
  if (disabled || !history || history.length === 0) return;
3822
3491
  if (key.upArrow) {
@@ -3894,7 +3563,7 @@ function UserInput({ value, onChange, onSubmit, disabled, history }) {
3894
3563
  ]
3895
3564
  }
3896
3565
  );
3897
- }
3566
+ });
3898
3567
 
3899
3568
  // src/repl.tsx
3900
3569
  init_providers();
@@ -3918,32 +3587,38 @@ function getContextLimit3(model) {
3918
3587
  function REPL({ initialPrompt }) {
3919
3588
  const { model: initialModel, systemPromptOverride } = useDarkfooContext();
3920
3589
  const { exit } = useApp();
3921
- const [model, setModel] = useState3(initialModel);
3922
- const [messages, setMessages] = useState3([]);
3923
- const [inputValue, setInputValue] = useState3("");
3924
- const [isStreaming, setIsStreaming] = useState3(false);
3925
- const [streamingText, setStreamingText] = useState3("");
3926
- const [activeTool, setActiveTool] = useState3(null);
3927
- const [toolResults, setToolResults] = useState3([]);
3928
- const [commandOutput, setCommandOutput] = useState3(null);
3929
- const [inputHistory, setInputHistory] = useState3([]);
3930
- const [tokenCounts, setTokenCounts] = useState3({ input: 0, output: 0 });
3931
- const [systemPrompt, setSystemPrompt] = useState3("");
3932
- const [foxMood, setFoxMood] = useState3("idle");
3933
- const [providerOnline, setProviderOnline] = useState3(true);
3934
- const abortRef = useRef2(null);
3935
- const hasRun = useRef2(false);
3936
- const sessionId = useRef2(createSessionId());
3590
+ const [model, setModel] = useState2(initialModel);
3591
+ const [messages, setMessages] = useState2([]);
3592
+ const [inputValue, setInputValue] = useState2("");
3593
+ const [isStreaming, setIsStreaming] = useState2(false);
3594
+ const [streamingText, setStreamingText] = useState2("");
3595
+ const [activeTool, setActiveTool] = useState2(null);
3596
+ const [toolResults, setToolResults] = useState2([]);
3597
+ const [commandOutput, setCommandOutput] = useState2(null);
3598
+ const [inputHistory, setInputHistory] = useState2([]);
3599
+ const [tokenCounts, setTokenCounts] = useState2({ input: 0, output: 0 });
3600
+ const [systemPrompt, setSystemPrompt] = useState2("");
3601
+ const [foxMood, setFoxMood] = useState2("idle");
3602
+ const [providerOnline, setProviderOnline] = useState2(true);
3603
+ const abortRef = useRef(null);
3604
+ const hasRun = useRef(false);
3605
+ const sessionId = useRef(createSessionId());
3606
+ const messagesRef = useRef(messages);
3607
+ messagesRef.current = messages;
3608
+ const modelRef = useRef(model);
3609
+ modelRef.current = model;
3610
+ const systemPromptRef = useRef(systemPrompt);
3611
+ systemPromptRef.current = systemPrompt;
3937
3612
  const tools = getTools();
3938
3613
  const cwd = process.cwd();
3939
- useEffect2(() => {
3614
+ useEffect(() => {
3940
3615
  if (systemPromptOverride) {
3941
3616
  setSystemPrompt(systemPromptOverride);
3942
3617
  } else {
3943
3618
  buildSystemPrompt(tools, cwd).then(setSystemPrompt);
3944
3619
  }
3945
3620
  }, []);
3946
- useEffect2(() => {
3621
+ useEffect(() => {
3947
3622
  const provider = getProvider();
3948
3623
  provider.healthCheck().then((ok) => {
3949
3624
  setProviderOnline(ok);
@@ -3975,15 +3650,17 @@ function REPL({ initialPrompt }) {
3975
3650
  setModel("");
3976
3651
  });
3977
3652
  }, []);
3978
- const commandContext = {
3653
+ const clearMessages = useCallback2(() => setMessages([]), []);
3654
+ const commandContextRef = useRef({
3979
3655
  messages,
3980
3656
  model,
3981
3657
  cwd,
3982
3658
  setModel,
3983
- clearMessages: () => setMessages([]),
3659
+ clearMessages,
3984
3660
  exit,
3985
3661
  tokenCounts
3986
- };
3662
+ });
3663
+ commandContextRef.current = { messages, model, cwd, setModel, clearMessages, exit, tokenCounts };
3987
3664
  const addToHistory = useCallback2((input) => {
3988
3665
  setInputHistory((prev) => {
3989
3666
  const filtered = prev.filter((h) => h !== input);
@@ -4006,17 +3683,19 @@ function REPL({ initialPrompt }) {
4006
3683
  setFoxMood("thinking");
4007
3684
  const controller = new AbortController();
4008
3685
  abortRef.current = controller;
4009
- const allMessages = [...messages, userMsg];
3686
+ const allMessages = [...messagesRef.current, userMsg];
3687
+ const currentModel = modelRef.current;
3688
+ const currentSystemPrompt = systemPromptRef.current;
4010
3689
  setTokenCounts((prev) => ({
4011
3690
  ...prev,
4012
3691
  input: prev.input + Math.ceil(userMessage.length / 4)
4013
3692
  }));
4014
3693
  try {
4015
3694
  for await (const event of query({
4016
- model,
3695
+ model: currentModel,
4017
3696
  messages: allMessages,
4018
3697
  tools,
4019
- systemPrompt,
3698
+ systemPrompt: currentSystemPrompt,
4020
3699
  signal: controller.signal
4021
3700
  })) {
4022
3701
  if (controller.signal.aborted) break;
@@ -4040,7 +3719,7 @@ function REPL({ initialPrompt }) {
4040
3719
  case "assistant_message":
4041
3720
  setMessages((prev) => {
4042
3721
  const updated = [...prev, event.message];
4043
- saveSession(sessionId.current, updated, model, cwd).catch(() => {
3722
+ saveSession(sessionId.current, updated, currentModel, cwd).catch(() => {
4044
3723
  });
4045
3724
  return updated;
4046
3725
  });
@@ -4077,7 +3756,7 @@ function REPL({ initialPrompt }) {
4077
3756
  abortRef.current = null;
4078
3757
  }
4079
3758
  },
4080
- [model, messages, tools, systemPrompt]
3759
+ [tools, cwd]
4081
3760
  );
4082
3761
  const handleSubmit = useCallback2(
4083
3762
  async (value) => {
@@ -4090,7 +3769,7 @@ function REPL({ initialPrompt }) {
4090
3769
  return;
4091
3770
  }
4092
3771
  if (value.startsWith("/")) {
4093
- const result = await dispatchCommand(value, commandContext);
3772
+ const result = await dispatchCommand(value, commandContextRef.current);
4094
3773
  if (result) {
4095
3774
  if (result.replaceMessages) {
4096
3775
  setMessages(result.replaceMessages);
@@ -4131,16 +3810,16 @@ function REPL({ initialPrompt }) {
4131
3810
  }
4132
3811
  runQuery(value);
4133
3812
  },
4134
- [addToHistory, commandContext, cwd, runQuery]
3813
+ [addToHistory, exit, cwd, runQuery]
4135
3814
  );
4136
- useEffect2(() => {
3815
+ useEffect(() => {
4137
3816
  if (initialPrompt && !hasRun.current) {
4138
3817
  hasRun.current = true;
4139
3818
  runQuery(initialPrompt);
4140
3819
  }
4141
3820
  }, [initialPrompt, runQuery]);
4142
- const autoCompactRef = useRef2(false);
4143
- useEffect2(() => {
3821
+ const autoCompactRef = useRef(false);
3822
+ useEffect(() => {
4144
3823
  if (isStreaming || autoCompactRef.current || messages.length < 6) return;
4145
3824
  const totalChars = messages.reduce((sum, m) => sum + m.content.length, 0);
4146
3825
  const estTokens = Math.ceil(totalChars / 4) + 2e3;
@@ -4192,14 +3871,11 @@ ${result.content}
4192
3871
  isStreaming && streamingText ? /* @__PURE__ */ jsxs7(Box7, { marginBottom: 1, children: [
4193
3872
  /* @__PURE__ */ jsx8(Text7, { color: theme.cyan, children: "\u23BF " }),
4194
3873
  /* @__PURE__ */ jsx8(Text7, { color: theme.text, wrap: "wrap", children: streamingText }),
4195
- /* @__PURE__ */ jsxs7(Text7, { color: theme.cyan, children: [
4196
- " ",
4197
- /* @__PURE__ */ jsx8(Spinner2, { type: "dots" })
4198
- ] })
3874
+ /* @__PURE__ */ jsx8(Text7, { color: theme.dim, children: " ..." })
4199
3875
  ] }) : null,
4200
3876
  isStreaming && !streamingText && !activeTool ? /* @__PURE__ */ jsxs7(Box7, { marginLeft: 2, children: [
4201
- /* @__PURE__ */ jsx8(Text7, { color: theme.cyan, children: /* @__PURE__ */ jsx8(Spinner2, { type: "dots" }) }),
4202
- /* @__PURE__ */ jsx8(Text7, { color: theme.dim, children: " Thinking..." })
3877
+ /* @__PURE__ */ jsx8(Text7, { color: theme.cyan, children: "..." }),
3878
+ /* @__PURE__ */ jsx8(Text7, { color: theme.dim, children: " Thinking" })
4203
3879
  ] }) : null,
4204
3880
  /* @__PURE__ */ jsxs7(Box7, { children: [
4205
3881
  /* @__PURE__ */ jsx8(Box7, { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx8(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "darkfoo-code",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Darkfoo Code — local AI coding assistant powered by Ollama, vLLM, llama.cpp, and other LLM providers",
5
5
  "type": "module",
6
6
  "license": "MIT",