sharkbait 1.0.26 → 1.0.28

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/cli.js +130 -72
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1428,7 +1428,20 @@ async function isBeadsFunctional() {
1428
1428
  return { functional: true, useNoDb: false };
1429
1429
  }
1430
1430
  } catch {}
1431
- if (bdSupportsNoDb()) {
1431
+ try {
1432
+ const result = await exec([BD_PATH, "list", "--json", "--no-db"], { cwd: process.cwd() });
1433
+ if (result.exitCode === 0) {
1434
+ forceNoDb = true;
1435
+ return { functional: true, useNoDb: true };
1436
+ }
1437
+ } catch {}
1438
+ if (tryFixMetadataBackend()) {
1439
+ try {
1440
+ const result = await exec([BD_PATH, "list", "--json"], { cwd: process.cwd() });
1441
+ if (result.exitCode === 0) {
1442
+ return { functional: true, useNoDb: true };
1443
+ }
1444
+ } catch {}
1432
1445
  try {
1433
1446
  const result = await exec([BD_PATH, "list", "--json", "--no-db"], { cwd: process.cwd() });
1434
1447
  if (result.exitCode === 0) {
@@ -1437,7 +1450,7 @@ async function isBeadsFunctional() {
1437
1450
  }
1438
1451
  } catch {}
1439
1452
  }
1440
- return { functional: false, error: "bd list failed (dolt unreachable and --no-db fallback failed)" };
1453
+ return { functional: false, error: "bd list failed (dolt unreachable, --no-db failed, metadata fix failed)" };
1441
1454
  }
1442
1455
  async function isBdInstalled() {
1443
1456
  try {
@@ -1447,13 +1460,25 @@ async function isBdInstalled() {
1447
1460
  return false;
1448
1461
  }
1449
1462
  }
1450
- function bdSupportsNoDb() {
1463
+ function tryFixMetadataBackend(cwd) {
1464
+ const dir = cwd || process.cwd();
1465
+ const metadataPath = join3(dir, ".beads", "metadata.json");
1451
1466
  try {
1452
- const help = execSync(`${BD_PATH} init --help 2>&1`, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
1453
- return help.includes("--no-db");
1454
- } catch {
1455
- return false;
1456
- }
1467
+ if (!existsSync3(metadataPath))
1468
+ return false;
1469
+ const { readFileSync, writeFileSync } = __require("fs");
1470
+ const raw = readFileSync(metadataPath, "utf-8");
1471
+ const meta = JSON.parse(raw);
1472
+ if (meta.backend === "dolt" || meta.database === "dolt") {
1473
+ meta.backend = "no-db";
1474
+ meta.database = "no-db";
1475
+ delete meta.dolt_mode;
1476
+ delete meta.dolt_database;
1477
+ writeFileSync(metadataPath, JSON.stringify(meta, null, 2));
1478
+ return true;
1479
+ }
1480
+ } catch {}
1481
+ return false;
1457
1482
  }
1458
1483
  var beadsTools = [
1459
1484
  {
@@ -1590,18 +1615,27 @@ var beadsTools = [
1590
1615
  alreadyInitialized: true
1591
1616
  };
1592
1617
  }
1593
- if (bdSupportsNoDb()) {
1594
- try {
1595
- const result = await exec([BD_PATH, "init", "--no-db"], { cwd: process.cwd() });
1596
- if (result.exitCode === 0) {
1597
- return {
1598
- success: true,
1599
- message: "Beads reinitialized in no-db mode (dolt was not reachable).",
1600
- output: result.stdout.trim(),
1601
- mode: "no-db"
1602
- };
1603
- }
1604
- } catch {}
1618
+ try {
1619
+ const result = await exec([BD_PATH, "init", "--no-db"], { cwd: process.cwd() });
1620
+ if (result.exitCode === 0) {
1621
+ tryFixMetadataBackend();
1622
+ return {
1623
+ success: true,
1624
+ message: "Beads reinitialized in no-db mode (dolt was not reachable).",
1625
+ output: result.stdout.trim(),
1626
+ mode: "no-db"
1627
+ };
1628
+ }
1629
+ } catch {}
1630
+ if (tryFixMetadataBackend()) {
1631
+ const { functional: nowFunctional } = await isBeadsFunctional();
1632
+ if (nowFunctional) {
1633
+ return {
1634
+ success: true,
1635
+ message: "Beads metadata fixed — switched from dolt to no-db mode.",
1636
+ mode: "no-db"
1637
+ };
1638
+ }
1605
1639
  }
1606
1640
  return {
1607
1641
  success: false,
@@ -1609,34 +1643,28 @@ var beadsTools = [
1609
1643
  proceedWithoutBeads: true
1610
1644
  };
1611
1645
  }
1612
- const args = [BD_PATH, "init"];
1613
- if (noDb && bdSupportsNoDb()) {
1614
- args.push("--no-db");
1615
- }
1616
1646
  try {
1617
- const result = await exec(args, { cwd: process.cwd() });
1618
- if (result.exitCode !== 0) {
1619
- if (!noDb && bdSupportsNoDb()) {
1620
- const fallback = await exec([BD_PATH, "init", "--no-db"], { cwd: process.cwd() });
1621
- if (fallback.exitCode === 0) {
1622
- return {
1623
- success: true,
1624
- message: "Beads initialized in no-db mode (dolt not available, using JSONL).",
1625
- output: fallback.stdout.trim(),
1626
- mode: "no-db"
1627
- };
1628
- }
1629
- }
1647
+ const result = await exec([BD_PATH, "init", "--no-db"], { cwd: process.cwd() });
1648
+ if (result.exitCode === 0) {
1630
1649
  return {
1631
- success: false,
1632
- message: `Failed to initialize beads: ${result.stderr || result.stdout}. Proceed with the task without beads.`,
1633
- proceedWithoutBeads: true
1650
+ success: true,
1651
+ message: "Beads initialized in no-db mode (JSONL-backed, no dolt dependency).",
1652
+ output: result.stdout.trim(),
1653
+ mode: "no-db"
1654
+ };
1655
+ }
1656
+ const fallback = await exec([BD_PATH, "init"], { cwd: process.cwd() });
1657
+ if (fallback.exitCode === 0) {
1658
+ return {
1659
+ success: true,
1660
+ message: "Beads initialized successfully.",
1661
+ output: fallback.stdout.trim()
1634
1662
  };
1635
1663
  }
1636
1664
  return {
1637
- success: true,
1638
- message: "Beads initialized successfully.",
1639
- output: result.stdout.trim()
1665
+ success: false,
1666
+ message: `Failed to initialize beads: ${fallback.stderr || fallback.stdout}. Proceed with the task without beads.`,
1667
+ proceedWithoutBeads: true
1640
1668
  };
1641
1669
  } catch (error) {
1642
1670
  return {
@@ -1822,7 +1850,7 @@ var beadsTools = [
1822
1850
  return JSON.parse(result.stdout);
1823
1851
  }
1824
1852
  } catch {}
1825
- if (!forceNoDb && bdSupportsNoDb()) {
1853
+ if (!forceNoDb) {
1826
1854
  try {
1827
1855
  const noDbArgs = [...args, "--no-db"];
1828
1856
  const result = await exec(noDbArgs);
@@ -1832,6 +1860,14 @@ var beadsTools = [
1832
1860
  }
1833
1861
  } catch {}
1834
1862
  }
1863
+ if (tryFixMetadataBackend()) {
1864
+ try {
1865
+ const result = await exec(bdArgs("list", "--json"));
1866
+ if (result.exitCode === 0) {
1867
+ return JSON.parse(result.stdout);
1868
+ }
1869
+ } catch {}
1870
+ }
1835
1871
  try {
1836
1872
  const { readFileSync, readdirSync: readdirSync2 } = await import("fs");
1837
1873
  const beadsDir = join3(process.cwd(), ".beads");
@@ -3561,17 +3597,23 @@ Revise your approach based on what we've learned.`
3561
3597
  content: fullContent,
3562
3598
  tool_calls: toolCalls
3563
3599
  });
3564
- const toolResults = await Promise.allSettled(toolCalls.map(async (call) => {
3600
+ const parsedArgs = [];
3601
+ for (let i = 0;i < toolCalls.length; i++) {
3602
+ const call = toolCalls[i];
3565
3603
  let args;
3566
3604
  try {
3567
3605
  args = JSON.parse(call.function.arguments);
3568
3606
  } catch (parseErr) {
3569
- throw new Error(`Invalid tool arguments for ${call.function.name}: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`);
3607
+ args = {};
3570
3608
  }
3609
+ parsedArgs.push(args);
3610
+ yield { type: "tool_start", name: call.function.name, args };
3611
+ }
3612
+ const toolResults = await Promise.allSettled(toolCalls.map(async (call, i) => {
3571
3613
  return {
3572
3614
  call,
3573
- args,
3574
- result: await this.tools.execute(call.function.name, args)
3615
+ args: parsedArgs[i],
3616
+ result: await this.tools.execute(call.function.name, parsedArgs[i])
3575
3617
  };
3576
3618
  }));
3577
3619
  for (let i = 0;i < toolResults.length; i++) {
@@ -3579,7 +3621,6 @@ Revise your approach based on what we've learned.`
3579
3621
  const settled = toolResults[i];
3580
3622
  if (settled.status === "fulfilled") {
3581
3623
  const { args, result } = settled.value;
3582
- yield { type: "tool_start", name: call.function.name, args };
3583
3624
  yield { type: "tool_result", name: call.function.name, result };
3584
3625
  this.messages.push({
3585
3626
  role: "tool",
@@ -3602,7 +3643,6 @@ Revise your approach based on what we've learned.`
3602
3643
  progressLedger.lastProgressAt = new Date;
3603
3644
  } else {
3604
3645
  const errorMsg = getErrorMessage(settled.reason);
3605
- yield { type: "tool_start", name: call.function.name, args: {} };
3606
3646
  yield { type: "tool_error", name: call.function.name, error: errorMsg };
3607
3647
  this.messages.push({
3608
3648
  role: "tool",
@@ -7009,7 +7049,7 @@ function Spinner({
7009
7049
  useEffect(() => {
7010
7050
  const timer = setInterval(() => {
7011
7051
  setFrameIndex((prev) => (prev + 1) % frames.length);
7012
- }, 200);
7052
+ }, 300);
7013
7053
  return () => clearInterval(timer);
7014
7054
  }, [frames.length]);
7015
7055
  return /* @__PURE__ */ jsxDEV3(Box3, {
@@ -8574,13 +8614,16 @@ function App({ contextFiles: initialContextFiles, enableBeads: initialBeadsEnabl
8574
8614
  return config.azure.deployment;
8575
8615
  });
8576
8616
  const abortControllerRef = useRef(null);
8617
+ const RENDER_INTERVAL = 150;
8577
8618
  const pendingOutputRef = useRef("");
8578
8619
  const pendingTokensRef = useRef(0);
8579
8620
  const pendingCostRef = useRef(0);
8580
- const outputTimerRef = useRef(null);
8621
+ const activeToolCallsRef = useRef([]);
8622
+ const toolCallsDirtyRef = useRef(false);
8623
+ const renderTimerRef = useRef(null);
8581
8624
  const { exit } = useApp();
8582
8625
  const workingDir = currentDir;
8583
- const flushOutput = useCallback(() => {
8626
+ const flushRender = useCallback(() => {
8584
8627
  const output = pendingOutputRef.current;
8585
8628
  const reasoning = pendingReasoningRef.current;
8586
8629
  const tokens = pendingTokensRef.current;
@@ -8597,22 +8640,34 @@ function App({ contextFiles: initialContextFiles, enableBeads: initialBeadsEnabl
8597
8640
  setSessionCost((prev) => prev + cost);
8598
8641
  pendingCostRef.current = 0;
8599
8642
  }
8600
- outputTimerRef.current = null;
8643
+ if (toolCallsDirtyRef.current) {
8644
+ setActiveToolCalls([...activeToolCallsRef.current]);
8645
+ toolCallsDirtyRef.current = false;
8646
+ }
8647
+ renderTimerRef.current = null;
8601
8648
  }, []);
8649
+ const scheduleRender = useCallback(() => {
8650
+ if (!renderTimerRef.current) {
8651
+ renderTimerRef.current = setTimeout(flushRender, RENDER_INTERVAL);
8652
+ }
8653
+ }, [flushRender]);
8602
8654
  const throttledSetOutput = useCallback((content, chunkTokens) => {
8603
8655
  pendingOutputRef.current = content;
8604
8656
  if (chunkTokens && chunkTokens > 0) {
8605
8657
  pendingTokensRef.current += chunkTokens;
8606
8658
  pendingCostRef.current += chunkTokens * 0.00003;
8607
8659
  }
8608
- if (!outputTimerRef.current) {
8609
- outputTimerRef.current = setTimeout(flushOutput, 80);
8610
- }
8611
- }, [flushOutput]);
8660
+ scheduleRender();
8661
+ }, [scheduleRender]);
8662
+ const updateToolCalls = useCallback((updater) => {
8663
+ activeToolCallsRef.current = updater(activeToolCallsRef.current);
8664
+ toolCallsDirtyRef.current = true;
8665
+ scheduleRender();
8666
+ }, [scheduleRender]);
8612
8667
  useEffect2(() => {
8613
8668
  return () => {
8614
- if (outputTimerRef.current)
8615
- clearTimeout(outputTimerRef.current);
8669
+ if (renderTimerRef.current)
8670
+ clearTimeout(renderTimerRef.current);
8616
8671
  };
8617
8672
  }, []);
8618
8673
  const agent = React5.useMemo(() => new Agent({
@@ -8766,6 +8821,9 @@ function App({ contextFiles: initialContextFiles, enableBeads: initialBeadsEnabl
8766
8821
  setCurrentOutput("");
8767
8822
  setCurrentReasoning("");
8768
8823
  pendingReasoningRef.current = "";
8824
+ pendingOutputRef.current = "";
8825
+ activeToolCallsRef.current = [];
8826
+ toolCallsDirtyRef.current = false;
8769
8827
  setActiveToolCalls([]);
8770
8828
  const inputTokens = estimateTokens(userMessage);
8771
8829
  setTokenCount((prev) => prev + inputTokens);
@@ -8780,9 +8838,7 @@ function App({ contextFiles: initialContextFiles, enableBeads: initialBeadsEnabl
8780
8838
  switch (event.type) {
8781
8839
  case "reasoning":
8782
8840
  pendingReasoningRef.current += event.content;
8783
- if (!outputTimerRef.current) {
8784
- outputTimerRef.current = setTimeout(flushOutput, 80);
8785
- }
8841
+ scheduleRender();
8786
8842
  break;
8787
8843
  case "text":
8788
8844
  assistantContent += event.content;
@@ -8849,12 +8905,12 @@ ${event.consolidated}`,
8849
8905
  status: "running",
8850
8906
  startTime: Date.now()
8851
8907
  };
8852
- setActiveToolCalls((prev) => [...prev, newTool]);
8908
+ updateToolCalls((prev) => [...prev, newTool]);
8853
8909
  break;
8854
8910
  }
8855
8911
  case "tool_result": {
8856
8912
  const duration = event.duration;
8857
- setActiveToolCalls((prev) => {
8913
+ updateToolCalls((prev) => {
8858
8914
  const updated = prev.map((tc) => tc.name === event.name && tc.status === "running" ? {
8859
8915
  ...tc,
8860
8916
  status: "success",
@@ -8871,7 +8927,7 @@ ${event.consolidated}`,
8871
8927
  }
8872
8928
  case "tool_error": {
8873
8929
  const duration = event.duration;
8874
- setActiveToolCalls((prev) => prev.map((tc) => tc.name === event.name && tc.status === "running" ? {
8930
+ updateToolCalls((prev) => prev.map((tc) => tc.name === event.name && tc.status === "running" ? {
8875
8931
  ...tc,
8876
8932
  status: "error",
8877
8933
  duration,
@@ -8883,9 +8939,9 @@ ${event.consolidated}`,
8883
8939
  setTokenCount(event.totalTokens);
8884
8940
  break;
8885
8941
  case "done":
8886
- if (outputTimerRef.current) {
8887
- clearTimeout(outputTimerRef.current);
8888
- outputTimerRef.current = null;
8942
+ if (renderTimerRef.current) {
8943
+ clearTimeout(renderTimerRef.current);
8944
+ renderTimerRef.current = null;
8889
8945
  }
8890
8946
  if (pendingTokensRef.current > 0) {
8891
8947
  setTokenCount((prev) => prev + pendingTokensRef.current);
@@ -8897,7 +8953,8 @@ ${event.consolidated}`,
8897
8953
  }
8898
8954
  pendingOutputRef.current = "";
8899
8955
  pendingReasoningRef.current = "";
8900
- setCurrentReasoning("");
8956
+ activeToolCallsRef.current = [];
8957
+ toolCallsDirtyRef.current = false;
8901
8958
  if (assistantContent.trim()) {
8902
8959
  setMessages((prev) => [...prev, {
8903
8960
  role: "assistant",
@@ -8907,6 +8964,7 @@ ${event.consolidated}`,
8907
8964
  }]);
8908
8965
  }
8909
8966
  setCurrentOutput("");
8967
+ setCurrentReasoning("");
8910
8968
  setActiveToolCalls([]);
8911
8969
  setCurrentAgent(null);
8912
8970
  setThinkingMessage(null);
@@ -9089,7 +9147,7 @@ ${event.consolidated}`,
9089
9147
  }
9090
9148
 
9091
9149
  // src/version.ts
9092
- var VERSION = "1.0.26";
9150
+ var VERSION = "1.0.28";
9093
9151
 
9094
9152
  // src/agent/start-chat.ts
9095
9153
  async function startChat(options = {}) {
@@ -10373,7 +10431,7 @@ ${"━".repeat(60)}`);
10373
10431
  }
10374
10432
 
10375
10433
  // src/version.ts
10376
- var VERSION2 = "1.0.26";
10434
+ var VERSION2 = "1.0.28";
10377
10435
 
10378
10436
  // src/ui/logo.tsx
10379
10437
  import { Box as Box14, Text as Text14 } from "ink";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sharkbait",
3
- "version": "1.0.26",
3
+ "version": "1.0.28",
4
4
  "description": "AI-powered coding assistant for the command line. Uses OpenAI Responses API (not Chat). Autonomous agents, parallel code reviews, 36 tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/cli.js",