@mragentix/cli 4.2.37 → 4.2.39
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.
- package/dist/cli.js +179 -8
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +64 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +13 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/branding.d.ts +11 -0
- package/dist/core/branding.d.ts.map +1 -0
- package/dist/core/branding.js +11 -0
- package/dist/core/branding.js.map +1 -0
- package/dist/core/compaction/compactor.d.ts +1 -0
- package/dist/core/compaction/compactor.d.ts.map +1 -1
- package/dist/core/compaction/compactor.js +8 -1
- package/dist/core/compaction/compactor.js.map +1 -1
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/skills.d.ts +2 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +8 -8
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +97 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/update.d.ts +34 -0
- package/dist/core/update.d.ts.map +1 -0
- package/dist/core/update.js +231 -0
- package/dist/core/update.js.map +1 -0
- package/dist/interactive.d.ts.map +1 -1
- package/dist/interactive.js +17 -5
- package/dist/interactive.js.map +1 -1
- package/dist/modes/json-mode.d.ts.map +1 -1
- package/dist/modes/json-mode.js +2 -1
- package/dist/modes/json-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +2 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc-mode.js +2 -1
- package/dist/modes/rpc-mode.js.map +1 -1
- package/dist/modes/serve-mode.d.ts.map +1 -1
- package/dist/modes/serve-mode.js +7 -6
- package/dist/modes/serve-mode.js.map +1 -1
- package/dist/system-prompt.d.ts +1 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +40 -2
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/bash.d.ts +3 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +4 -1
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit-diff.test.d.ts +2 -0
- package/dist/tools/edit-diff.test.d.ts.map +1 -0
- package/dist/tools/edit-diff.test.js +67 -0
- package/dist/tools/edit-diff.test.js.map +1 -0
- package/dist/tools/edit.d.ts +3 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +4 -1
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/edit.test.d.ts +2 -0
- package/dist/tools/edit.test.d.ts.map +1 -0
- package/dist/tools/edit.test.js +93 -0
- package/dist/tools/edit.test.js.map +1 -0
- package/dist/tools/enter-plan.d.ts +8 -0
- package/dist/tools/enter-plan.d.ts.map +1 -0
- package/dist/tools/enter-plan.js +28 -0
- package/dist/tools/enter-plan.js.map +1 -0
- package/dist/tools/exit-plan.d.ts +8 -0
- package/dist/tools/exit-plan.d.ts.map +1 -0
- package/dist/tools/exit-plan.js +36 -0
- package/dist/tools/exit-plan.js.map +1 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +20 -4
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/path-utils.test.d.ts +2 -0
- package/dist/tools/path-utils.test.d.ts.map +1 -0
- package/dist/tools/path-utils.test.js +49 -0
- package/dist/tools/path-utils.test.js.map +1 -0
- package/dist/tools/plan-mode.test.d.ts +2 -0
- package/dist/tools/plan-mode.test.d.ts.map +1 -0
- package/dist/tools/plan-mode.test.js +214 -0
- package/dist/tools/plan-mode.test.js.map +1 -0
- package/dist/tools/read.test.d.ts +2 -0
- package/dist/tools/read.test.d.ts.map +1 -0
- package/dist/tools/read.test.js +81 -0
- package/dist/tools/read.test.js.map +1 -0
- package/dist/tools/skill.d.ts +10 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +36 -0
- package/dist/tools/skill.js.map +1 -0
- package/dist/tools/subagent.d.ts +3 -1
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +4 -1
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/truncate-utils.test.d.ts +2 -0
- package/dist/tools/truncate-utils.test.d.ts.map +1 -0
- package/dist/tools/truncate-utils.test.js +93 -0
- package/dist/tools/truncate-utils.test.js.map +1 -0
- package/dist/tools/web-fetch.js +1 -1
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/tools/write.d.ts +3 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +11 -1
- package/dist/tools/write.js.map +1 -1
- package/dist/tools/write.test.js +65 -52
- package/dist/tools/write.test.js.map +1 -1
- package/dist/ui/App.d.ts +18 -1
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +343 -31
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/ActivityIndicator.d.ts +2 -1
- package/dist/ui/components/ActivityIndicator.d.ts.map +1 -1
- package/dist/ui/components/ActivityIndicator.js +25 -4
- package/dist/ui/components/ActivityIndicator.js.map +1 -1
- package/dist/ui/components/AssistantMessage.d.ts.map +1 -1
- package/dist/ui/components/AssistantMessage.js +6 -1
- package/dist/ui/components/AssistantMessage.js.map +1 -1
- package/dist/ui/components/Banner.d.ts.map +1 -1
- package/dist/ui/components/Banner.js +12 -6
- package/dist/ui/components/Banner.js.map +1 -1
- package/dist/ui/components/Footer.d.ts +2 -1
- package/dist/ui/components/Footer.d.ts.map +1 -1
- package/dist/ui/components/Footer.js +30 -16
- package/dist/ui/components/Footer.js.map +1 -1
- package/dist/ui/components/InputArea.d.ts +3 -1
- package/dist/ui/components/InputArea.d.ts.map +1 -1
- package/dist/ui/components/InputArea.js +27 -17
- package/dist/ui/components/InputArea.js.map +1 -1
- package/dist/ui/components/Markdown.d.ts +5 -1
- package/dist/ui/components/Markdown.d.ts.map +1 -1
- package/dist/ui/components/Markdown.js +14 -6
- package/dist/ui/components/Markdown.js.map +1 -1
- package/dist/ui/components/PlanApproval.d.ts +8 -0
- package/dist/ui/components/PlanApproval.d.ts.map +1 -0
- package/dist/ui/components/PlanApproval.js +58 -0
- package/dist/ui/components/PlanApproval.js.map +1 -0
- package/dist/ui/components/PlanBanner.d.ts +6 -0
- package/dist/ui/components/PlanBanner.d.ts.map +1 -0
- package/dist/ui/components/PlanBanner.js +28 -0
- package/dist/ui/components/PlanBanner.js.map +1 -0
- package/dist/ui/components/PlanOverlay.d.ts +11 -0
- package/dist/ui/components/PlanOverlay.d.ts.map +1 -0
- package/dist/ui/components/PlanOverlay.js +267 -0
- package/dist/ui/components/PlanOverlay.js.map +1 -0
- package/dist/ui/components/ServerToolExecution.d.ts.map +1 -1
- package/dist/ui/components/ServerToolExecution.js +11 -3
- package/dist/ui/components/ServerToolExecution.js.map +1 -1
- package/dist/ui/components/SkillsOverlay.d.ts +7 -0
- package/dist/ui/components/SkillsOverlay.d.ts.map +1 -0
- package/dist/ui/components/SkillsOverlay.js +158 -0
- package/dist/ui/components/SkillsOverlay.js.map +1 -0
- package/dist/ui/components/Spinner.js +1 -1
- package/dist/ui/components/Spinner.js.map +1 -1
- package/dist/ui/components/StreamingArea.d.ts +2 -1
- package/dist/ui/components/StreamingArea.d.ts.map +1 -1
- package/dist/ui/components/StreamingArea.js +7 -2
- package/dist/ui/components/StreamingArea.js.map +1 -1
- package/dist/ui/components/SubAgentPanel.d.ts.map +1 -1
- package/dist/ui/components/SubAgentPanel.js +21 -11
- package/dist/ui/components/SubAgentPanel.js.map +1 -1
- package/dist/ui/components/TaskOverlay.d.ts.map +1 -1
- package/dist/ui/components/TaskOverlay.js +8 -8
- package/dist/ui/components/TaskOverlay.js.map +1 -1
- package/dist/ui/components/ToolExecution.d.ts.map +1 -1
- package/dist/ui/components/ToolExecution.js +33 -13
- package/dist/ui/components/ToolExecution.js.map +1 -1
- package/dist/ui/components/ToolGroupExecution.js +1 -1
- package/dist/ui/components/ToolGroupExecution.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts +8 -0
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +318 -236
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/ui/hooks/useTerminalSize.d.ts +18 -16
- package/dist/ui/hooks/useTerminalSize.d.ts.map +1 -1
- package/dist/ui/hooks/useTerminalSize.js +31 -24
- package/dist/ui/hooks/useTerminalSize.js.map +1 -1
- package/dist/ui/login.d.ts.map +1 -1
- package/dist/ui/login.js +1 -5
- package/dist/ui/login.js.map +1 -1
- package/dist/ui/render.d.ts +11 -0
- package/dist/ui/render.d.ts.map +1 -1
- package/dist/ui/render.js +7 -2
- package/dist/ui/render.js.map +1 -1
- package/dist/ui/sessions.d.ts.map +1 -1
- package/dist/ui/sessions.js +1 -5
- package/dist/ui/sessions.js.map +1 -1
- package/dist/ui/theme/dark.json +3 -1
- package/dist/ui/theme/light.json +3 -1
- package/dist/ui/theme/theme.d.ts +2 -0
- package/dist/ui/theme/theme.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/ui/App.js
CHANGED
|
@@ -21,8 +21,10 @@ import { ActivityIndicator } from "./components/ActivityIndicator.js";
|
|
|
21
21
|
import { InputArea } from "./components/InputArea.js";
|
|
22
22
|
import { Footer } from "./components/Footer.js";
|
|
23
23
|
import { Banner } from "./components/Banner.js";
|
|
24
|
+
import { PlanOverlay } from "./components/PlanOverlay.js";
|
|
24
25
|
import { ModelSelector } from "./components/ModelSelector.js";
|
|
25
26
|
import { TaskOverlay } from "./components/TaskOverlay.js";
|
|
27
|
+
import { SkillsOverlay } from "./components/SkillsOverlay.js";
|
|
26
28
|
import { BackgroundTasksBar } from "./components/BackgroundTasksBar.js";
|
|
27
29
|
import { useTheme } from "./theme/theme.js";
|
|
28
30
|
import { useAnimationTick, deriveFrame } from "./components/AnimationContext.js";
|
|
@@ -36,7 +38,9 @@ import { shouldCompact, compact } from "../core/compaction/compactor.js";
|
|
|
36
38
|
import { estimateConversationTokens } from "../core/compaction/token-estimator.js";
|
|
37
39
|
import { PROMPT_COMMANDS, getPromptCommand } from "../core/prompt-commands.js";
|
|
38
40
|
import { loadCustomCommands } from "../core/custom-commands.js";
|
|
41
|
+
import { buildSystemPrompt } from "../system-prompt.js";
|
|
39
42
|
import { getMCPServers } from "../core/mcp/index.js";
|
|
43
|
+
import { fetchUpstreamChanges, mergeUpstream, restoreBranding, bumpVersion, buildAll, publishToNpm, pushToGithub, selfUpdate, } from "../core/update.js";
|
|
40
44
|
import { trimFlushedItems, flushOnTurnText, flushOnTurnEnd } from "./live-item-flush.js";
|
|
41
45
|
// ── Provider Error Hints ──────────────────────────────────
|
|
42
46
|
/** Detect provider-side errors and return a user-facing hint. */
|
|
@@ -224,7 +228,7 @@ function markTaskInProgress(cwd, taskId) {
|
|
|
224
228
|
export function App(props) {
|
|
225
229
|
const theme = useTheme();
|
|
226
230
|
const { stdout } = useStdout();
|
|
227
|
-
const { resizeKey } = useTerminalSize();
|
|
231
|
+
const { columns, resizeKey } = useTerminalSize();
|
|
228
232
|
// Terminal title — updated later after agentLoop is created
|
|
229
233
|
// (hoisted here so the hook is always called in the same order)
|
|
230
234
|
const [titlePhase, setTitlePhase] = useState("idle");
|
|
@@ -260,6 +264,9 @@ export function App(props) {
|
|
|
260
264
|
const [currentTools, setCurrentTools] = useState(props.tools);
|
|
261
265
|
const [thinkingEnabled, setThinkingEnabled] = useState(!!props.thinking);
|
|
262
266
|
const messagesRef = useRef(props.messages);
|
|
267
|
+
const [planMode, setPlanMode] = useState(false);
|
|
268
|
+
const [planAutoExpand, setPlanAutoExpand] = useState(false);
|
|
269
|
+
const approvedPlanPathRef = useRef(undefined);
|
|
263
270
|
const nextIdRef = useRef(0);
|
|
264
271
|
const sessionManagerRef = useRef(props.sessionsDir ? new SessionManager(props.sessionsDir) : null);
|
|
265
272
|
const sessionPathRef = useRef(props.sessionPath);
|
|
@@ -284,6 +291,56 @@ export function App(props) {
|
|
|
284
291
|
useEffect(() => {
|
|
285
292
|
reloadCustomCommands();
|
|
286
293
|
}, [reloadCustomCommands]);
|
|
294
|
+
// ── Plan mode wiring ─────────────────────────────────────
|
|
295
|
+
// Sync planModeRef with React state
|
|
296
|
+
useEffect(() => {
|
|
297
|
+
if (props.planModeRef) {
|
|
298
|
+
props.planModeRef.current = planMode;
|
|
299
|
+
}
|
|
300
|
+
}, [planMode, props.planModeRef]);
|
|
301
|
+
// Rebuild system prompt when plan mode changes
|
|
302
|
+
useEffect(() => {
|
|
303
|
+
void (async () => {
|
|
304
|
+
const newPrompt = await buildSystemPrompt(props.cwd, props.skills, planMode, approvedPlanPathRef.current);
|
|
305
|
+
if (messagesRef.current[0]?.role === "system") {
|
|
306
|
+
messagesRef.current[0] = {
|
|
307
|
+
role: "system",
|
|
308
|
+
content: newPrompt,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
})();
|
|
312
|
+
}, [planMode, props.cwd, props.skills]);
|
|
313
|
+
// Wire onEnterPlan callback ref
|
|
314
|
+
useEffect(() => {
|
|
315
|
+
if (props.onEnterPlanRef) {
|
|
316
|
+
props.onEnterPlanRef.current = (reason) => {
|
|
317
|
+
setPlanMode(true);
|
|
318
|
+
const msg = reason ? `Plan mode activated: ${reason}` : "Plan mode activated";
|
|
319
|
+
setLiveItems((prev) => [...prev, { kind: "info", text: msg, id: getId() }]);
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
}, [props.onEnterPlanRef]);
|
|
323
|
+
// Wire onExitPlan callback ref
|
|
324
|
+
useEffect(() => {
|
|
325
|
+
if (props.onExitPlanRef) {
|
|
326
|
+
props.onExitPlanRef.current = async (planPath) => {
|
|
327
|
+
// Deactivate plan mode, store approved plan path, open pane
|
|
328
|
+
setPlanMode(false);
|
|
329
|
+
approvedPlanPathRef.current = planPath;
|
|
330
|
+
// Use setTimeout to open pane after the current tool execution completes,
|
|
331
|
+
// so the turn can finish and the UI transitions cleanly
|
|
332
|
+
setTimeout(() => {
|
|
333
|
+
stdout?.write("\x1b[2J\x1b[3J\x1b[H");
|
|
334
|
+
setPlanAutoExpand(true);
|
|
335
|
+
setOverlay("plan");
|
|
336
|
+
}, 300);
|
|
337
|
+
return ("Plan submitted. Exiting plan mode.\n" +
|
|
338
|
+
"The plan pane is opening for user review.\n" +
|
|
339
|
+
"Plan saved at: " +
|
|
340
|
+
planPath);
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
}, [props.onExitPlanRef, stdout]);
|
|
287
344
|
const persistNewMessages = useCallback(async () => {
|
|
288
345
|
const sm = sessionManagerRef.current;
|
|
289
346
|
const sp = sessionPathRef.current;
|
|
@@ -730,6 +787,7 @@ export function App(props) {
|
|
|
730
787
|
onAborted: useCallback(() => {
|
|
731
788
|
log("WARN", "agent", "Agent run aborted by user");
|
|
732
789
|
setRunAllTasks(false);
|
|
790
|
+
setDoneStatus(null);
|
|
733
791
|
setLiveItems((prev) => {
|
|
734
792
|
const next = prev.map((item) => {
|
|
735
793
|
if (item.kind === "subagent_group")
|
|
@@ -772,6 +830,34 @@ export function App(props) {
|
|
|
772
830
|
return [...next, { kind: "info", text: "Request was stopped.", id: getId() }];
|
|
773
831
|
});
|
|
774
832
|
}, []),
|
|
833
|
+
onQueuedStart: useCallback((content) => {
|
|
834
|
+
// When a queued message starts processing, show it as a UserItem
|
|
835
|
+
// and flush prior items to history
|
|
836
|
+
const displayText = typeof content === "string"
|
|
837
|
+
? content
|
|
838
|
+
: content
|
|
839
|
+
.filter((c) => c.type === "text")
|
|
840
|
+
.map((c) => c.text)
|
|
841
|
+
.join("\n");
|
|
842
|
+
const imageCount = typeof content === "string"
|
|
843
|
+
? undefined
|
|
844
|
+
: content.filter((c) => c.type === "image").length || undefined;
|
|
845
|
+
setLiveItems((prev) => {
|
|
846
|
+
if (prev.length > 0) {
|
|
847
|
+
setHistory((h) => compactHistory([...h, ...trimFlushedItems(prev)]));
|
|
848
|
+
}
|
|
849
|
+
return [];
|
|
850
|
+
});
|
|
851
|
+
const userItem = {
|
|
852
|
+
kind: "user",
|
|
853
|
+
text: displayText,
|
|
854
|
+
imageCount,
|
|
855
|
+
id: getId(),
|
|
856
|
+
};
|
|
857
|
+
setLastUserMessage(displayText);
|
|
858
|
+
setDoneStatus(null);
|
|
859
|
+
setLiveItems([userItem]);
|
|
860
|
+
}, []),
|
|
775
861
|
});
|
|
776
862
|
// Phase 2 of the two-phase flush: after onDone clears liveItems (phase 1)
|
|
777
863
|
// and Ink renders the smaller live area (updating its internal line
|
|
@@ -837,6 +923,137 @@ export function App(props) {
|
|
|
837
923
|
setLiveItems([{ kind: "info", text: "Session cleared.", id: getId() }]);
|
|
838
924
|
return;
|
|
839
925
|
}
|
|
926
|
+
// Handle /plan — toggle plan mode
|
|
927
|
+
if (trimmed === "/plan" || trimmed === "/plan on") {
|
|
928
|
+
setPlanMode(true);
|
|
929
|
+
setLiveItems((prev) => [
|
|
930
|
+
...prev,
|
|
931
|
+
{ kind: "info", text: "Plan mode activated", id: getId() },
|
|
932
|
+
]);
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
if (trimmed === "/plan off") {
|
|
936
|
+
setPlanMode(false);
|
|
937
|
+
setLiveItems((prev) => [
|
|
938
|
+
...prev,
|
|
939
|
+
{ kind: "info", text: "Plan mode deactivated", id: getId() },
|
|
940
|
+
]);
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
// Handle /update — upstream sync pipeline
|
|
944
|
+
if (trimmed === "/update" || trimmed === "/u") {
|
|
945
|
+
try {
|
|
946
|
+
const status = fetchUpstreamChanges();
|
|
947
|
+
if (!status.hasUpdates) {
|
|
948
|
+
setLiveItems((prev) => [
|
|
949
|
+
...prev,
|
|
950
|
+
{ kind: "info", text: "✅ Already up to date with upstream.", id: getId() },
|
|
951
|
+
]);
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
const commitList = status.commits.map((c) => ` ${c}`).join("\n");
|
|
955
|
+
const msg = [
|
|
956
|
+
`📦 Found ${status.commits.length} new commit(s) from upstream:\n`,
|
|
957
|
+
commitList,
|
|
958
|
+
"",
|
|
959
|
+
status.diffStat,
|
|
960
|
+
"",
|
|
961
|
+
"Run /update confirm to merge, build, and publish.",
|
|
962
|
+
].join("\n");
|
|
963
|
+
setLiveItems((prev) => [...prev, { kind: "info", text: msg, id: getId() }]);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
catch (err) {
|
|
967
|
+
setLiveItems((prev) => [
|
|
968
|
+
...prev,
|
|
969
|
+
{ kind: "error", message: `${err.message}`, id: getId() },
|
|
970
|
+
]);
|
|
971
|
+
}
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
if (trimmed === "/update confirm") {
|
|
975
|
+
setLiveItems((prev) => [
|
|
976
|
+
...prev,
|
|
977
|
+
{ kind: "info", text: "🔄 Running update pipeline...", id: getId() },
|
|
978
|
+
]);
|
|
979
|
+
try {
|
|
980
|
+
const steps = [];
|
|
981
|
+
steps.push("🔄 Merging upstream changes...");
|
|
982
|
+
const merge = mergeUpstream();
|
|
983
|
+
if (!merge.ok) {
|
|
984
|
+
steps.push(` ❌ ${merge.error}`);
|
|
985
|
+
setLiveItems((prev) => [
|
|
986
|
+
...prev,
|
|
987
|
+
{ kind: "error", message: steps.join("\n"), id: getId() },
|
|
988
|
+
]);
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
steps.push(" ✓ Merged");
|
|
992
|
+
steps.push("🎨 Restoring branding...");
|
|
993
|
+
const branding = restoreBranding();
|
|
994
|
+
steps.push(` ✓ ${branding.filesModified} file(s) updated`);
|
|
995
|
+
steps.push("📝 Bumping version...");
|
|
996
|
+
const version = bumpVersion();
|
|
997
|
+
steps.push(` ✓ ${version.oldVersion} → ${version.newVersion}`);
|
|
998
|
+
steps.push("🔨 Building all packages...");
|
|
999
|
+
const build = buildAll();
|
|
1000
|
+
if (!build.ok) {
|
|
1001
|
+
steps.push(` ❌ Build failed:\n${build.output}`);
|
|
1002
|
+
setLiveItems((prev) => [
|
|
1003
|
+
...prev,
|
|
1004
|
+
{ kind: "error", message: steps.join("\n"), id: getId() },
|
|
1005
|
+
]);
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
steps.push(" ✓ Built");
|
|
1009
|
+
steps.push("📦 Publishing to npm...");
|
|
1010
|
+
const pub = publishToNpm();
|
|
1011
|
+
for (const r of pub.results)
|
|
1012
|
+
steps.push(` ${r}`);
|
|
1013
|
+
if (!pub.ok) {
|
|
1014
|
+
setLiveItems((prev) => [
|
|
1015
|
+
...prev,
|
|
1016
|
+
{ kind: "error", message: steps.join("\n"), id: getId() },
|
|
1017
|
+
]);
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
steps.push("🚀 Pushing to GitHub...");
|
|
1021
|
+
const push = pushToGithub(version.newVersion);
|
|
1022
|
+
if (!push.ok) {
|
|
1023
|
+
steps.push(` ❌ ${push.error}`);
|
|
1024
|
+
setLiveItems((prev) => [
|
|
1025
|
+
...prev,
|
|
1026
|
+
{ kind: "error", message: steps.join("\n"), id: getId() },
|
|
1027
|
+
]);
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
steps.push(" ✓ Pushed");
|
|
1031
|
+
steps.push("⬆️ Updating global install...");
|
|
1032
|
+
const update = selfUpdate();
|
|
1033
|
+
steps.push(update.ok ? " ✓ Updated" : ` ⚠️ Self-update failed: ${update.output}`);
|
|
1034
|
+
steps.push("");
|
|
1035
|
+
steps.push(`✅ Updated to v${version.newVersion}! Restart mragentix to use the new version.`);
|
|
1036
|
+
setLiveItems((prev) => [...prev, { kind: "info", text: steps.join("\n"), id: getId() }]);
|
|
1037
|
+
}
|
|
1038
|
+
catch (err) {
|
|
1039
|
+
setLiveItems((prev) => [
|
|
1040
|
+
...prev,
|
|
1041
|
+
{
|
|
1042
|
+
kind: "error",
|
|
1043
|
+
message: `Pipeline error: ${err.message}`,
|
|
1044
|
+
id: getId(),
|
|
1045
|
+
},
|
|
1046
|
+
]);
|
|
1047
|
+
}
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
// Handle /plans — open plan pane
|
|
1051
|
+
if (trimmed === "/plans") {
|
|
1052
|
+
stdout?.write("\x1b[2J\x1b[3J\x1b[H");
|
|
1053
|
+
setPlanAutoExpand(false);
|
|
1054
|
+
setOverlay("plan");
|
|
1055
|
+
return;
|
|
1056
|
+
}
|
|
840
1057
|
// Handle prompt-template commands (built-in + custom from .mragentix/commands/)
|
|
841
1058
|
if (trimmed.startsWith("/")) {
|
|
842
1059
|
const parts = trimmed.slice(1).split(" ");
|
|
@@ -890,31 +1107,8 @@ export function App(props) {
|
|
|
890
1107
|
return;
|
|
891
1108
|
}
|
|
892
1109
|
}
|
|
893
|
-
//
|
|
894
|
-
setLiveItems((prev) => {
|
|
895
|
-
if (prev.length > 0) {
|
|
896
|
-
setHistory((h) => compactHistory([...h, ...trimFlushedItems(prev)]));
|
|
897
|
-
}
|
|
898
|
-
return [];
|
|
899
|
-
});
|
|
900
|
-
// Build display text — strip image paths, show badges instead
|
|
1110
|
+
// ── Build user content (shared by normal + queued paths) ──
|
|
901
1111
|
const hasImages = inputImages.length > 0;
|
|
902
|
-
let displayText = input;
|
|
903
|
-
if (hasImages) {
|
|
904
|
-
const { cleanText } = await extractImagePaths(input, props.cwd);
|
|
905
|
-
displayText = cleanText;
|
|
906
|
-
}
|
|
907
|
-
const userItem = {
|
|
908
|
-
kind: "user",
|
|
909
|
-
text: displayText,
|
|
910
|
-
imageCount: hasImages ? inputImages.length : undefined,
|
|
911
|
-
pasteInfo,
|
|
912
|
-
id: getId(),
|
|
913
|
-
};
|
|
914
|
-
setLastUserMessage(input);
|
|
915
|
-
setDoneStatus(null);
|
|
916
|
-
setLiveItems([userItem]);
|
|
917
|
-
// Build user content — plain string or content array with images
|
|
918
1112
|
const modelInfo = getModel(currentModel);
|
|
919
1113
|
const modelSupportsImages = modelInfo?.supportsImages ?? true;
|
|
920
1114
|
let userContent;
|
|
@@ -958,6 +1152,47 @@ export function App(props) {
|
|
|
958
1152
|
else {
|
|
959
1153
|
userContent = input;
|
|
960
1154
|
}
|
|
1155
|
+
// ── Queue message if agent is already running ──
|
|
1156
|
+
if (agentLoop.isRunning) {
|
|
1157
|
+
log("INFO", "queue", `Queued message: ${trimmed.length > 80 ? trimmed.slice(0, 80) + "..." : trimmed}`);
|
|
1158
|
+
agentLoop.queueMessage(userContent);
|
|
1159
|
+
let displayText = input;
|
|
1160
|
+
if (hasImages) {
|
|
1161
|
+
const { cleanText } = await extractImagePaths(input, props.cwd);
|
|
1162
|
+
displayText = cleanText;
|
|
1163
|
+
}
|
|
1164
|
+
const queuedItem = {
|
|
1165
|
+
kind: "queued",
|
|
1166
|
+
text: displayText,
|
|
1167
|
+
imageCount: hasImages ? inputImages.length : undefined,
|
|
1168
|
+
id: getId(),
|
|
1169
|
+
};
|
|
1170
|
+
setLiveItems((prev) => [...prev, queuedItem]);
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
// Move any remaining live items into history (Static) before starting new turn
|
|
1174
|
+
setLiveItems((prev) => {
|
|
1175
|
+
if (prev.length > 0) {
|
|
1176
|
+
setHistory((h) => compactHistory([...h, ...trimFlushedItems(prev)]));
|
|
1177
|
+
}
|
|
1178
|
+
return [];
|
|
1179
|
+
});
|
|
1180
|
+
// Build display text — strip image paths, show badges instead
|
|
1181
|
+
let displayText = input;
|
|
1182
|
+
if (hasImages) {
|
|
1183
|
+
const { cleanText } = await extractImagePaths(input, props.cwd);
|
|
1184
|
+
displayText = cleanText;
|
|
1185
|
+
}
|
|
1186
|
+
const userItem = {
|
|
1187
|
+
kind: "user",
|
|
1188
|
+
text: displayText,
|
|
1189
|
+
imageCount: hasImages ? inputImages.length : undefined,
|
|
1190
|
+
pasteInfo,
|
|
1191
|
+
id: getId(),
|
|
1192
|
+
};
|
|
1193
|
+
setLastUserMessage(input);
|
|
1194
|
+
setDoneStatus(null);
|
|
1195
|
+
setLiveItems([userItem]);
|
|
961
1196
|
// Run agent
|
|
962
1197
|
try {
|
|
963
1198
|
await agentLoop.run(userContent);
|
|
@@ -976,6 +1211,7 @@ export function App(props) {
|
|
|
976
1211
|
}, [agentLoop, props.onSlashCommand, compactConversation]);
|
|
977
1212
|
const handleAbort = useCallback(() => {
|
|
978
1213
|
if (agentLoop.isRunning) {
|
|
1214
|
+
agentLoop.clearQueue();
|
|
979
1215
|
agentLoop.abort();
|
|
980
1216
|
}
|
|
981
1217
|
else {
|
|
@@ -1064,6 +1300,9 @@ export function App(props) {
|
|
|
1064
1300
|
{ name: "compact", aliases: ["c"], description: "Compact conversation" },
|
|
1065
1301
|
{ name: "clear", aliases: [], description: "Clear session and terminal" },
|
|
1066
1302
|
{ name: "quit", aliases: ["q", "exit"], description: "Exit the agent" },
|
|
1303
|
+
{ name: "plan", aliases: [], description: "Toggle plan mode (on/off)" },
|
|
1304
|
+
{ name: "plans", aliases: [], description: "Open plans pane" },
|
|
1305
|
+
{ name: "update", aliases: ["u"], description: "Pull upstream changes, rebuild & publish" },
|
|
1067
1306
|
...PROMPT_COMMANDS.map((cmd) => ({
|
|
1068
1307
|
name: cmd.name,
|
|
1069
1308
|
aliases: cmd.aliases,
|
|
@@ -1099,10 +1338,14 @@ export function App(props) {
|
|
|
1099
1338
|
return (_jsx(ServerToolExecution, { status: "done", name: item.name, input: item.input, durationMs: item.durationMs, resultType: item.resultType }, item.id));
|
|
1100
1339
|
case "error": {
|
|
1101
1340
|
const providerHint = getProviderErrorHint(item.message);
|
|
1102
|
-
return (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { color: theme.error, children: ["✗ ", item.message] }), providerHint && (_jsxs(Text, { color: theme.textDim, children: [" Hint: ", providerHint] }))] }, item.id));
|
|
1341
|
+
return (_jsxs(Box, { marginTop: 1, flexDirection: "column", flexShrink: 1, children: [_jsxs(Text, { color: theme.error, wrap: "wrap", children: ["✗ ", item.message] }), providerHint && (_jsxs(Text, { color: theme.textDim, wrap: "wrap", children: [" Hint: ", providerHint] }))] }, item.id));
|
|
1103
1342
|
}
|
|
1104
1343
|
case "info":
|
|
1105
|
-
return (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.textDim, children: item.text }) }, item.id));
|
|
1344
|
+
return (_jsx(Box, { marginTop: 1, flexShrink: 1, children: _jsx(Text, { color: theme.textDim, wrap: "wrap", children: item.text }) }, item.id));
|
|
1345
|
+
case "queued":
|
|
1346
|
+
return (_jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: theme.accent, bold: true, children: "⏳ Queued: " }), _jsxs(Text, { color: theme.text, wrap: "wrap", children: [item.text, item.imageCount
|
|
1347
|
+
? ` (+${item.imageCount} image${item.imageCount > 1 ? "s" : ""})`
|
|
1348
|
+
: ""] })] }, item.id));
|
|
1106
1349
|
case "compacting":
|
|
1107
1350
|
return _jsx(CompactionSpinner, {}, item.id);
|
|
1108
1351
|
case "compacted":
|
|
@@ -1165,7 +1408,10 @@ export function App(props) {
|
|
|
1165
1408
|
runAllTasksRef.current = runAllTasks;
|
|
1166
1409
|
}, [runAllTasks]);
|
|
1167
1410
|
const isTaskView = overlay === "tasks";
|
|
1168
|
-
|
|
1411
|
+
const isSkillsView = overlay === "skills";
|
|
1412
|
+
const isPlanView = overlay === "plan";
|
|
1413
|
+
const isOverlayView = isTaskView || isSkillsView || isPlanView;
|
|
1414
|
+
return (_jsxs(Box, { flexDirection: "column", width: columns, children: [_jsx(Static, { items: isOverlayView ? [] : history, style: { width: "100%" }, children: (item) => (_jsx(Box, { flexDirection: "column", paddingRight: 1, children: renderItem(item) }, item.id)) }, `${resizeKey}-${staticKey}`), isTaskView ? (_jsx(TaskOverlay, { cwd: props.cwd, agentRunning: agentLoop.isRunning, onClose: () => {
|
|
1169
1415
|
stdout?.write("\x1b[2J\x1b[3J\x1b[H");
|
|
1170
1416
|
setTaskCount(getTaskCount(props.cwd));
|
|
1171
1417
|
setStaticKey((k) => k + 1);
|
|
@@ -1181,11 +1427,77 @@ export function App(props) {
|
|
|
1181
1427
|
markTaskInProgress(props.cwd, next.id);
|
|
1182
1428
|
startTask(next.title, next.prompt, next.id);
|
|
1183
1429
|
}
|
|
1184
|
-
} })) :
|
|
1430
|
+
} })) : isSkillsView ? (_jsx(SkillsOverlay, { cwd: props.cwd, onClose: () => {
|
|
1431
|
+
stdout?.write("\x1b[2J\x1b[3J\x1b[H");
|
|
1432
|
+
setStaticKey((k) => k + 1);
|
|
1433
|
+
setOverlay(null);
|
|
1434
|
+
} })) : isPlanView ? (_jsx(PlanOverlay, { cwd: props.cwd, autoExpandNewest: planAutoExpand, onClose: () => {
|
|
1435
|
+
stdout?.write("\x1b[2J\x1b[3J\x1b[H");
|
|
1436
|
+
setStaticKey((k) => k + 1);
|
|
1437
|
+
setPlanAutoExpand(false);
|
|
1438
|
+
setOverlay(null);
|
|
1439
|
+
}, onApprove: (planPath) => {
|
|
1440
|
+
// Store approved plan path — will be injected into the new system prompt
|
|
1441
|
+
approvedPlanPathRef.current = planPath;
|
|
1442
|
+
// Clear session for a fresh context focused on the plan
|
|
1443
|
+
stdout?.write("\x1b[2J\x1b[3J\x1b[H");
|
|
1444
|
+
setHistory([{ kind: "banner", id: "banner" }]);
|
|
1445
|
+
setLiveItems([]);
|
|
1446
|
+
setStaticKey((k) => k + 1);
|
|
1447
|
+
setPlanAutoExpand(false);
|
|
1448
|
+
setOverlay(null);
|
|
1449
|
+
// Rebuild system prompt with the approved plan, then reset the session
|
|
1450
|
+
void (async () => {
|
|
1451
|
+
const newPrompt = await buildSystemPrompt(props.cwd, props.skills, false, planPath);
|
|
1452
|
+
messagesRef.current = [{ role: "system", content: newPrompt }];
|
|
1453
|
+
agentLoop.reset();
|
|
1454
|
+
persistedIndexRef.current = messagesRef.current.length;
|
|
1455
|
+
// Create a new session file
|
|
1456
|
+
const sm = sessionManagerRef.current;
|
|
1457
|
+
if (sm) {
|
|
1458
|
+
const s = await sm.create(props.cwd, currentProvider, currentModel);
|
|
1459
|
+
sessionPathRef.current = s.path;
|
|
1460
|
+
}
|
|
1461
|
+
// Start implementation with a clean context
|
|
1462
|
+
setLiveItems([
|
|
1463
|
+
{
|
|
1464
|
+
kind: "info",
|
|
1465
|
+
text: "Plan approved — starting fresh session for implementation",
|
|
1466
|
+
id: getId(),
|
|
1467
|
+
},
|
|
1468
|
+
]);
|
|
1469
|
+
setDoneStatus(null);
|
|
1470
|
+
await agentLoop.run("The plan has been approved. Implement it now, following each step in order.");
|
|
1471
|
+
})();
|
|
1472
|
+
}, onReject: (planPath, feedback) => {
|
|
1473
|
+
stdout?.write("\x1b[2J\x1b[3J\x1b[H");
|
|
1474
|
+
setStaticKey((k) => k + 1);
|
|
1475
|
+
setPlanAutoExpand(false);
|
|
1476
|
+
setOverlay(null);
|
|
1477
|
+
// Send rejection + feedback to the agent
|
|
1478
|
+
const msg = `The plan at ${planPath} was rejected.\n\nFeedback: ${feedback}\n\n` +
|
|
1479
|
+
`Please revise the plan based on this feedback.`;
|
|
1480
|
+
setLiveItems((prev) => [
|
|
1481
|
+
...prev,
|
|
1482
|
+
{ kind: "info", text: `Plan rejected — "${feedback}"`, id: getId() },
|
|
1483
|
+
]);
|
|
1484
|
+
void agentLoop.run(msg);
|
|
1485
|
+
} })) : (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingRight: 1, children: [liveItems.map((item) => renderItem(item)), _jsx(StreamingArea, { isRunning: agentLoop.isRunning, streamingText: agentLoop.streamingText, streamingThinking: agentLoop.streamingThinking, showThinking: props.showThinking, thinkingMs: agentLoop.thinkingMs, planMode: planMode })] }), agentLoop.isRunning && agentLoop.activityPhase !== "idle" ? (_jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: agentLoop.activityPhase === "thinking"
|
|
1185
1486
|
? THINKING_BORDER_COLORS[thinkingBorderFrame]
|
|
1186
|
-
: "transparent", paddingLeft: 1, paddingRight: 1, children: _jsx(ActivityIndicator, { phase: agentLoop.activityPhase, elapsedMs: agentLoop.elapsedMs, thinkingMs: agentLoop.thinkingMs, isThinking: agentLoop.isThinking, tokenEstimate: agentLoop.streamedTokenEstimate, userMessage: lastUserMessage, activeToolNames: agentLoop.activeToolCalls.map((tc) => tc.name) }) })) : (doneStatus && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.success, children: ["✻ ", doneStatus.verb, " ", formatDuration(doneStatus.durationMs)] }) }))), _jsx(InputArea, { onSubmit: handleSubmit, onAbort: handleAbort, disabled: agentLoop.isRunning, isActive: !taskBarFocused && !overlay, onDownAtEnd: handleFocusTaskBar, onShiftTab: handleToggleThinking, onToggleTasks: () => {
|
|
1487
|
+
: "transparent", paddingLeft: 1, paddingRight: 1, width: columns, children: _jsx(ActivityIndicator, { phase: agentLoop.activityPhase, elapsedMs: agentLoop.elapsedMs, thinkingMs: agentLoop.thinkingMs, isThinking: agentLoop.isThinking, tokenEstimate: agentLoop.streamedTokenEstimate, userMessage: lastUserMessage, activeToolNames: agentLoop.activeToolCalls.map((tc) => tc.name), planMode: planMode }) })) : (doneStatus && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.success, children: ["✻ ", doneStatus.verb, " ", formatDuration(doneStatus.durationMs)] }) }))), agentLoop.queuedCount > 0 && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.accent, children: ["⏳ ", agentLoop.queuedCount, " message", agentLoop.queuedCount > 1 ? "s" : "", " queued"] }) })), _jsx(InputArea, { onSubmit: handleSubmit, onAbort: handleAbort, disabled: agentLoop.isRunning, isActive: !taskBarFocused && !overlay, onDownAtEnd: handleFocusTaskBar, onShiftTab: handleToggleThinking, onToggleTasks: () => {
|
|
1187
1488
|
stdout?.write("\x1b[2J\x1b[3J\x1b[H");
|
|
1188
1489
|
setOverlay("tasks");
|
|
1189
|
-
},
|
|
1490
|
+
}, onToggleSkills: () => {
|
|
1491
|
+
stdout?.write("\x1b[2J\x1b[3J\x1b[H");
|
|
1492
|
+
setOverlay("skills");
|
|
1493
|
+
}, onTogglePlanMode: () => {
|
|
1494
|
+
const next = !planMode;
|
|
1495
|
+
setPlanMode(next);
|
|
1496
|
+
log("INFO", "plan", `Plan mode ${next ? "enabled" : "disabled"}`);
|
|
1497
|
+
setLiveItems((items) => [
|
|
1498
|
+
...items,
|
|
1499
|
+
{ kind: "info", text: `Plan mode ${next ? "on" : "off"}`, id: getId() },
|
|
1500
|
+
]);
|
|
1501
|
+
}, cwd: props.cwd, commands: allCommands }), overlay === "model" ? (_jsx(ModelSelector, { onSelect: handleModelSelect, onCancel: () => setOverlay(null), loggedInProviders: props.loggedInProviders ?? [currentProvider], currentModel: currentModel, currentProvider: currentProvider })) : (_jsx(Footer, { model: currentModel, tokensIn: agentLoop.contextUsed, cwd: props.cwd, gitBranch: gitBranch, thinkingEnabled: thinkingEnabled, planMode: planMode })), bgTasks.length > 0 && (_jsx(BackgroundTasksBar, { tasks: bgTasks, focused: taskBarFocused, expanded: taskBarExpanded, selectedIndex: selectedTaskIndex, onExpand: handleTaskBarExpand, onCollapse: handleTaskBarCollapse, onKill: handleTaskKill, onExit: handleTaskBarExit, onNavigate: handleTaskNavigate }))] }))] }));
|
|
1190
1502
|
}
|
|
1191
1503
|
//# sourceMappingURL=App.js.map
|