@nomad-e/bluma-cli 0.1.55 → 0.1.56

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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/main.js +120 -58
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  **BluMa** is a CLI-based model agent for advanced software engineering workflows. Built with React/Ink 5, it provides an interactive terminal interface for LLM-powered automation, code generation, refactoring, and task execution. Features persistent sessions, contextual reasoning, smart feedback, coordinator mode for worker orchestration, and extensible tools/skills architecture.
8
8
 
9
- **Current Version:** 0.1.47
9
+ **Current Version:** 0.1.55
10
10
 
11
11
  ---
12
12
 
package/dist/main.js CHANGED
@@ -15990,11 +15990,12 @@ Run: npm i -g ${BLUMA_PACKAGE_NAME} to update.`;
15990
15990
  }
15991
15991
  }
15992
15992
 
15993
- // src/app/ui/components/UpdateNotice.tsx
15993
+ // src/app/ui/components/StartupUpdateGate.tsx
15994
15994
  import { Box as Box17, Text as Text16 } from "ink";
15995
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
15995
+
15996
+ // src/app/ui/utils/update_message.ts
15996
15997
  function parseUpdateMessage(msg) {
15997
- const lines = msg.split(/\r?\n/).map((l) => l.trim());
15998
+ const lines = String(msg ?? "").split(/\r?\n/).map((l) => l.trim());
15998
15999
  const first = lines[0] || "";
15999
16000
  const hintLine = lines.slice(1).join(" ") || "";
16000
16001
  const nameMatch = first.match(/Update available for\s+([^!]+)!/i);
@@ -16006,19 +16007,38 @@ function parseUpdateMessage(msg) {
16006
16007
  hint: hintLine || void 0
16007
16008
  };
16008
16009
  }
16009
- var UpdateNotice = ({ message: message2 }) => {
16010
+ function extractInstallCommand(hint) {
16011
+ if (!hint) return null;
16012
+ const match = hint.match(/Run:\s*(.+?)(?:\s+to update\.?)?$/i);
16013
+ return match?.[1]?.trim() || null;
16014
+ }
16015
+
16016
+ // src/app/ui/components/StartupUpdateGate.tsx
16017
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
16018
+ var StartupUpdateGate = ({
16019
+ message: message2
16020
+ }) => {
16010
16021
  const { name, current, latest: latest2, hint } = parseUpdateMessage(message2);
16011
- return /* @__PURE__ */ jsx18(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", paddingLeft: 2, children: [
16012
- name && current && latest2 ? /* @__PURE__ */ jsx18(Text16, { color: BLUMA_TERMINAL.claude, bold: true, children: name }) : null,
16013
- name && current && latest2 ? /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
16022
+ const command = extractInstallCommand(hint);
16023
+ return /* @__PURE__ */ jsx18(ChatBlock, { marginBottom: 1, children: /* @__PURE__ */ jsxs16(Box17, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
16024
+ /* @__PURE__ */ jsxs16(Box17, { marginBottom: 1, children: [
16025
+ /* @__PURE__ */ jsx18(Text16, { color: BLUMA_TERMINAL.orange, children: "\u273B " }),
16026
+ /* @__PURE__ */ jsx18(Text16, { color: BLUMA_TERMINAL.blue, bold: true, children: "Blu" }),
16027
+ /* @__PURE__ */ jsx18(Text16, { color: BLUMA_TERMINAL.magenta, bold: true, children: "Ma" }),
16028
+ /* @__PURE__ */ jsx18(Text16, { dimColor: true, children: " update gate" })
16029
+ ] }),
16030
+ /* @__PURE__ */ jsx18(Text16, { bold: true, color: BLUMA_TERMINAL.claude, children: name || "New BluMa version available" }),
16031
+ current && latest2 ? /* @__PURE__ */ jsxs16(Text16, { dimColor: true, children: [
16014
16032
  current,
16015
16033
  " \u2192 ",
16016
16034
  latest2
16017
- ] }) : /* @__PURE__ */ jsx18(Text16, { dimColor: true, children: message2 }),
16018
- hint ? /* @__PURE__ */ jsx18(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text16, { dimColor: true, children: hint }) }) : null
16035
+ ] }) : null,
16036
+ /* @__PURE__ */ jsx18(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text16, { dimColor: true, wrap: "wrap", children: command ? `Run this command to update:
16037
+ ${command}` : hint || "An update is available for BluMa CLI." }) }),
16038
+ /* @__PURE__ */ jsx18(Box17, { marginTop: 1, children: /* @__PURE__ */ jsx18(Text16, { color: BLUMA_TERMINAL.warn, bold: true, children: "Press Enter to continue" }) })
16019
16039
  ] }) });
16020
16040
  };
16021
- var UpdateNotice_default = UpdateNotice;
16041
+ var StartupUpdateGate_default = StartupUpdateGate;
16022
16042
 
16023
16043
  // src/app/ui/components/ErrorMessage.tsx
16024
16044
  import { Box as Box18, Text as Text17 } from "ink";
@@ -16610,6 +16630,10 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
16610
16630
  "Initializing agent..."
16611
16631
  );
16612
16632
  const [toolsCount, setToolsCount] = useState11(null);
16633
+ const [startupPhase, setStartupPhase] = useState11("checking");
16634
+ const [startupUpdateMessage, setStartupUpdateMessage] = useState11(
16635
+ null
16636
+ );
16613
16637
  const [mcpStatus, setMcpStatus] = useState11(
16614
16638
  "connecting"
16615
16639
  );
@@ -16623,23 +16647,12 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
16623
16647
  const [pendingAskUserQuestions, setPendingAskUserQuestions] = useState11(null);
16624
16648
  const [showWorkers, setShowWorkers] = useState11(false);
16625
16649
  const [zoomedWorkerSession, setZoomedWorkerSession] = useState11(null);
16626
- useInput6((input, key) => {
16627
- if (key.ctrl && key.shift && input.toLowerCase() === "w") {
16628
- setShowWorkers((prev) => !prev);
16629
- }
16630
- if (key.escape && showWorkers) {
16631
- if (zoomedWorkerSession) {
16632
- setZoomedWorkerSession(null);
16633
- } else {
16634
- setShowWorkers(false);
16635
- }
16636
- }
16637
- });
16638
16650
  const [isInitAgentActive, setIsInitAgentActive] = useState11(false);
16639
16651
  const [liveToolName, setLiveToolName] = useState11(null);
16640
16652
  const [liveToolArgs, setLiveToolArgs] = useState11(void 0);
16641
16653
  const [isReasoning, setIsReasoning] = useState11(false);
16642
16654
  const alwaysAcceptList = useRef6([]);
16655
+ const agentInitializationStartedRef = useRef6(false);
16643
16656
  const workdir = process.cwd();
16644
16657
  const turnStartedAtRef = useRef6(null);
16645
16658
  const [processingStartMs, setProcessingStartMs] = useState11(null);
@@ -16673,6 +16686,33 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
16673
16686
  ];
16674
16687
  });
16675
16688
  }, []);
16689
+ const startAgentInitialization = useCallback4(async () => {
16690
+ if (agentInitializationStartedRef.current) return;
16691
+ agentInitializationStartedRef.current = true;
16692
+ try {
16693
+ agentInstance.current = new Agent(sessionId, eventBus);
16694
+ await agentInstance.current.initialize();
16695
+ appendHookEvent({
16696
+ type: "session:init",
16697
+ sessionId,
16698
+ summary: "agent initialized"
16699
+ });
16700
+ eventBus.emit("backend_message", {
16701
+ type: "status",
16702
+ status: "mcp_connected",
16703
+ tools: agentInstance.current.getAvailableTools().length
16704
+ });
16705
+ setStartupPhase("ready");
16706
+ } catch (error) {
16707
+ const errorMessage = error instanceof Error ? error.message : "Unknown error during Agent initialization.";
16708
+ setStartupPhase("failed");
16709
+ setStatusMessage(errorMessage);
16710
+ eventBus.emit("backend_message", {
16711
+ type: "error",
16712
+ message: errorMessage
16713
+ });
16714
+ }
16715
+ }, [eventBus, sessionId]);
16676
16716
  useEffect11(() => {
16677
16717
  expandPreviewHotkeyBus.on("expand", appendExpandPreviewToHistory);
16678
16718
  return () => {
@@ -16680,22 +16720,24 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
16680
16720
  };
16681
16721
  }, [appendExpandPreviewToHistory]);
16682
16722
  useEffect11(() => {
16683
- if (process.env.CI || blumaUpdateRegistryCheckStarted) return;
16723
+ if (process.env.CI || blumaUpdateRegistryCheckStarted) {
16724
+ setStartupPhase("starting-agent");
16725
+ void startAgentInitialization();
16726
+ return;
16727
+ }
16684
16728
  blumaUpdateRegistryCheckStarted = true;
16729
+ setStatusMessage("Checking for updates...");
16685
16730
  void checkForUpdates().then((msg) => {
16686
- if (!msg) return;
16687
- setHistory((prev) => {
16688
- const nextId2 = prev.length === 0 ? 1 : Math.max(...prev.map((h) => h.id), HEADER_PANEL_HISTORY_ID) + 1;
16689
- return [
16690
- ...prev,
16691
- {
16692
- id: nextId2,
16693
- component: /* @__PURE__ */ jsx27(UpdateNotice_default, { message: msg })
16694
- }
16695
- ];
16696
- });
16731
+ if (!msg) {
16732
+ setStartupPhase("starting-agent");
16733
+ void startAgentInitialization();
16734
+ return;
16735
+ }
16736
+ setStartupUpdateMessage(msg);
16737
+ setStartupPhase("update-available");
16738
+ setStatusMessage("Update available");
16697
16739
  });
16698
- }, []);
16740
+ }, [startAgentInitialization]);
16699
16741
  useEffect11(() => {
16700
16742
  setHistory((prev) => {
16701
16743
  const tail = prev.filter((h) => h.id !== HEADER_PANEL_HISTORY_ID);
@@ -16725,6 +16767,28 @@ var AppComponent = ({ eventBus, sessionId, cliVersion }) => {
16725
16767
  ];
16726
16768
  });
16727
16769
  }, [isProcessing, eventBus]);
16770
+ const continuePastUpdateGate = useCallback4(() => {
16771
+ if (startupPhase !== "update-available") return;
16772
+ setStartupPhase("starting-agent");
16773
+ setStatusMessage("Connecting to MCP...");
16774
+ void startAgentInitialization();
16775
+ }, [startupPhase, startAgentInitialization]);
16776
+ useInput6((input, key) => {
16777
+ if (startupPhase === "update-available" && (key.return || input === "\n" || input === "\r")) {
16778
+ continuePastUpdateGate();
16779
+ return;
16780
+ }
16781
+ if (key.ctrl && key.shift && input.toLowerCase() === "w") {
16782
+ setShowWorkers((prev) => !prev);
16783
+ }
16784
+ if (key.escape && showWorkers) {
16785
+ if (zoomedWorkerSession) {
16786
+ setZoomedWorkerSession(null);
16787
+ } else {
16788
+ setShowWorkers(false);
16789
+ }
16790
+ }
16791
+ });
16728
16792
  const handleSubmit = useCallback4(
16729
16793
  (text) => {
16730
16794
  if (!text || !agentInstance.current) return;
@@ -16980,28 +17044,6 @@ Please use command_status to check the result and report back to the user.`;
16980
17044
  }
16981
17045
  }, [history.length]);
16982
17046
  useEffect11(() => {
16983
- const initializeAgent = async () => {
16984
- try {
16985
- agentInstance.current = new Agent(sessionId, eventBus);
16986
- await agentInstance.current.initialize();
16987
- appendHookEvent({
16988
- type: "session:init",
16989
- sessionId,
16990
- summary: "agent initialized"
16991
- });
16992
- eventBus.emit("backend_message", {
16993
- type: "status",
16994
- status: "mcp_connected",
16995
- tools: agentInstance.current.getAvailableTools().length
16996
- });
16997
- } catch (error) {
16998
- const errorMessage = error instanceof Error ? error.message : "Unknown error during Agent initialization.";
16999
- eventBus.emit("backend_message", {
17000
- type: "error",
17001
- message: errorMessage
17002
- });
17003
- }
17004
- };
17005
17047
  const handleBackendMessage = (parsed) => {
17006
17048
  try {
17007
17049
  const appendTurnDurationIfAny = () => {
@@ -17256,7 +17298,6 @@ Please use command_status to check the result and report back to the user.`;
17256
17298
  uiEventBus.on("user_overlay", handleUiOverlay);
17257
17299
  uiEventBus.on("input_notice", handleInputNotice);
17258
17300
  eventBus.on("backend_message", handleBackendMessage);
17259
- initializeAgent();
17260
17301
  return () => {
17261
17302
  uiEventBus.off("user_overlay", handleUiOverlay);
17262
17303
  uiEventBus.off("input_notice", handleInputNotice);
@@ -17264,6 +17305,27 @@ Please use command_status to check the result and report back to the user.`;
17264
17305
  };
17265
17306
  }, [eventBus, sessionId, handleConfirmation]);
17266
17307
  const renderInteractiveComponent = () => {
17308
+ if (startupPhase === "checking") {
17309
+ return /* @__PURE__ */ jsx27(
17310
+ SessionInfoConnectingMCP_default,
17311
+ {
17312
+ workdir,
17313
+ statusMessage: statusMessage || "Checking for updates..."
17314
+ }
17315
+ );
17316
+ }
17317
+ if (startupPhase === "update-available" && startupUpdateMessage) {
17318
+ return /* @__PURE__ */ jsx27(StartupUpdateGate_default, { message: startupUpdateMessage });
17319
+ }
17320
+ if (startupPhase === "failed") {
17321
+ return /* @__PURE__ */ jsx27(Box26, { flexDirection: "column", children: /* @__PURE__ */ jsx27(
17322
+ ErrorMessage_default,
17323
+ {
17324
+ message: statusMessage || "Startup failed",
17325
+ hint: "Fix the error above and restart BluMa."
17326
+ }
17327
+ ) });
17328
+ }
17267
17329
  if (mcpStatus !== "connected") {
17268
17330
  return /* @__PURE__ */ jsx27(
17269
17331
  SessionInfoConnectingMCP_default,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomad-e/bluma-cli",
3
- "version": "0.1.55",
3
+ "version": "0.1.56",
4
4
  "description": "BluMa independent agent for automation and advanced software engineering.",
5
5
  "author": "Alex Fonseca",
6
6
  "license": "Apache-2.0",