@runfusion/fusion 0.2.4 → 0.2.6

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 (31) hide show
  1. package/dist/bin.js +311 -56
  2. package/dist/client/assets/{AgentDetailView-CkuuGA1O.js → AgentDetailView-CBdzWtd-.js} +1 -1
  3. package/dist/client/assets/{AgentsView-CWFLMIDP.js → AgentsView-DPlnCa_B.js} +3 -3
  4. package/dist/client/assets/{ChatView-C_T91ebd.js → ChatView-BXzYysNG.js} +1 -1
  5. package/dist/client/assets/{DevServerView-ChWTzTvy.js → DevServerView-BY5cGz23.js} +1 -1
  6. package/dist/client/assets/{DirectoryPicker-BMJIT7HD.js → DirectoryPicker-DZ90eSBn.js} +1 -1
  7. package/dist/client/assets/{DocumentsView-Co9to4Zp.css → DocumentsView-DV2DrCZb.css} +1 -1
  8. package/dist/client/assets/{DocumentsView-CjfVl8mZ.js → DocumentsView-lQwJmc4G.js} +1 -1
  9. package/dist/client/assets/{InsightsView-Rb735C9_.js → InsightsView-DUiZZ0z8.js} +1 -1
  10. package/dist/client/assets/{MemoryView-LLc_uNtG.js → MemoryView-DvSmMN6G.js} +1 -1
  11. package/dist/client/assets/{NodesView-BviqBWRA.js → NodesView-DgyM-ktg.js} +1 -1
  12. package/dist/client/assets/PiExtensionsManager-K7HQ08L4.css +1 -0
  13. package/dist/client/assets/PiExtensionsManager-wxB-q06A.js +11 -0
  14. package/dist/client/assets/{PluginManager-BywTPbLB.js → PluginManager-LH02ybSH.js} +1 -1
  15. package/dist/client/assets/PluginManager-tCFMZMLL.css +1 -0
  16. package/dist/client/assets/{RoadmapsView-Dhl--4vY.js → RoadmapsView-ANn2jmsU.js} +1 -1
  17. package/dist/client/assets/{SetupWizardModal-CVtmwoJC.js → SetupWizardModal-UxlAtKWA.js} +1 -1
  18. package/dist/client/assets/{SkillsView-CG9y4fsE.js → SkillsView-DEjGh7wW.js} +1 -1
  19. package/dist/client/assets/{folder-open-BVDq27HP.js → folder-open-J7yPbaCt.js} +1 -1
  20. package/dist/client/assets/index-BdJsO65L.css +1 -0
  21. package/dist/client/assets/index-CHoVMPAA.js +649 -0
  22. package/dist/client/assets/{upload-BDvpReDO.js → upload-B_grq4hM.js} +1 -1
  23. package/dist/client/index.html +2 -2
  24. package/dist/extension.js +70 -8
  25. package/dist/pi-claude-cli/package.json +1 -1
  26. package/package.json +5 -5
  27. package/dist/client/assets/PiExtensionsManager-CPgmJgDk.css +0 -1
  28. package/dist/client/assets/PiExtensionsManager-CriZBkQe.js +0 -11
  29. package/dist/client/assets/PluginManager-D64RIzmL.css +0 -1
  30. package/dist/client/assets/index-CikysL-d.js +0 -644
  31. package/dist/client/assets/index-Da1qmtc7.css +0 -1
package/dist/bin.js CHANGED
@@ -91,7 +91,10 @@ var init_settings_schema = __esm({
91
91
  settingsSyncConflictResolution: "last-write-wins",
92
92
  // Dashboard session state (persisted to global settings for PWA/offline restore)
93
93
  dashboardCurrentNodeId: void 0,
94
- dashboardCurrentProjectIdByNode: void 0
94
+ dashboardCurrentProjectIdByNode: void 0,
95
+ // Dashboard TUI memory guard
96
+ vitestAutoKillEnabled: true,
97
+ vitestKillThresholdPct: 90
95
98
  };
96
99
  DEFAULT_PROJECT_SETTINGS = {
97
100
  globalPause: false,
@@ -65592,6 +65595,63 @@ async function validateDiffScope(store, taskId, diffStat, strict = false) {
65592
65595
  }
65593
65596
  return result;
65594
65597
  }
65598
+ async function resolveTaskDiffBaseRef({
65599
+ cwd,
65600
+ headRef,
65601
+ baseBranch,
65602
+ baseCommitSha
65603
+ }) {
65604
+ const resolvedBaseBranch = baseBranch?.trim() || "main";
65605
+ const quotedHeadRef = quoteArg(headRef);
65606
+ let mergeBase;
65607
+ try {
65608
+ try {
65609
+ const { stdout } = await execAsync2(`git merge-base ${quotedHeadRef} ${quoteArg(resolvedBaseBranch)}`, {
65610
+ cwd,
65611
+ encoding: "utf-8"
65612
+ });
65613
+ mergeBase = stdout.trim() || void 0;
65614
+ } catch {
65615
+ const { stdout } = await execAsync2(`git merge-base ${quotedHeadRef} ${quoteArg(`origin/${resolvedBaseBranch}`)}`, {
65616
+ cwd,
65617
+ encoding: "utf-8"
65618
+ });
65619
+ mergeBase = stdout.trim() || void 0;
65620
+ }
65621
+ } catch {
65622
+ }
65623
+ if (mergeBase) {
65624
+ try {
65625
+ const { stdout } = await execAsync2(`git rev-parse ${quotedHeadRef}`, {
65626
+ cwd,
65627
+ encoding: "utf-8"
65628
+ });
65629
+ const headSha = stdout.trim();
65630
+ if (headSha && headSha !== mergeBase) return mergeBase;
65631
+ } catch {
65632
+ return mergeBase;
65633
+ }
65634
+ }
65635
+ if (baseCommitSha) {
65636
+ try {
65637
+ await execAsync2(`git merge-base --is-ancestor ${quoteArg(baseCommitSha)} ${quotedHeadRef}`, {
65638
+ cwd,
65639
+ encoding: "utf-8"
65640
+ });
65641
+ return baseCommitSha;
65642
+ } catch {
65643
+ }
65644
+ }
65645
+ try {
65646
+ const { stdout } = await execAsync2(`git rev-parse ${quoteArg(`${headRef}~1`)}`, {
65647
+ cwd,
65648
+ encoding: "utf-8"
65649
+ });
65650
+ return stdout.trim() || void 0;
65651
+ } catch {
65652
+ return void 0;
65653
+ }
65654
+ }
65595
65655
  async function getConflictedFiles(cwd) {
65596
65656
  try {
65597
65657
  const { stdout } = await execAsync2("git diff --name-only --diff-filter=U", {
@@ -66208,10 +66268,17 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
66208
66268
  mergerLog.warn(`${taskId}: pre-merge rebase pipeline failed (${msg}) \u2014 proceeding without rebase`);
66209
66269
  }
66210
66270
  }
66271
+ const diffBaseRef = await resolveTaskDiffBaseRef({
66272
+ cwd: rootDir,
66273
+ headRef: branch,
66274
+ baseBranch: task.baseBranch,
66275
+ baseCommitSha: task.baseCommitSha
66276
+ });
66277
+ const contextDiffRange = diffBaseRef ? `${diffBaseRef}..${branch}` : `HEAD..${branch}`;
66211
66278
  let commitLog = "";
66212
66279
  let diffStat = "";
66213
66280
  try {
66214
- const { stdout: logOutput } = await execAsync2(`git log HEAD..${branch} --format="- %s"`, {
66281
+ const { stdout: logOutput } = await execAsync2(`git log ${contextDiffRange} --format="- %s"`, {
66215
66282
  cwd: rootDir,
66216
66283
  encoding: "utf-8"
66217
66284
  });
@@ -66220,12 +66287,7 @@ async function aiMergeTask(store, rootDir, taskId, options = {}) {
66220
66287
  commitLog = "(unable to read commit log)";
66221
66288
  }
66222
66289
  try {
66223
- const { stdout: mergeBaseOutput } = await execAsync2(`git merge-base HEAD ${branch}`, {
66224
- cwd: rootDir,
66225
- encoding: "utf-8"
66226
- });
66227
- const mergeBase = mergeBaseOutput.trim();
66228
- const { stdout: diffOutput } = await execAsync2(`git diff ${mergeBase}..${branch} --stat`, {
66290
+ const { stdout: diffOutput } = await execAsync2(`git diff ${contextDiffRange} --stat`, {
66229
66291
  cwd: rootDir,
66230
66292
  encoding: "utf-8"
66231
66293
  });
@@ -87844,6 +87906,9 @@ function detectGenericUrl(line) {
87844
87906
  }
87845
87907
  return withSource("generic-url", genericUrlMatch[1]);
87846
87908
  }
87909
+ function isInspectorDiagnosticLine(line) {
87910
+ return /\b(?:inspector|debugger)\b/i.test(line) || /\b(node:)?\s*--inspect(?:-brk)?\b/i.test(line) || /\bws:\/\/(?:127\.0\.0\.1|localhost):\d{2,5}\b/i.test(line);
87911
+ }
87847
87912
  function detectGenericPortLine(line) {
87848
87913
  const keywordPortMatch = line.match(/\b(?:ready|listening|started|available|compiled|running|server)\b[^\d]{0,50}(?:on\s+)?(?:port\s*[:=]?\s*)?(\d{2,5})\b/i);
87849
87914
  if (!keywordPortMatch) {
@@ -87870,7 +87935,7 @@ function detectPortFromLogLine(line) {
87870
87935
  return null;
87871
87936
  }
87872
87937
  const cleanLine = stripAnsi(line).trim();
87873
- if (!cleanLine) {
87938
+ if (!cleanLine || isInspectorDiagnosticLine(cleanLine)) {
87874
87939
  return null;
87875
87940
  }
87876
87941
  return detectViteLine(cleanLine) ?? detectNextLine(cleanLine) ?? detectStorybookLine(cleanLine) ?? detectAngularLine(cleanLine) ?? detectGenericUrl(cleanLine) ?? detectGenericPortLine(cleanLine);
@@ -115277,6 +115342,38 @@ async function runGitCommand(args, cwd, timeout2 = 1e4) {
115277
115342
  }
115278
115343
  return "";
115279
115344
  }
115345
+ async function resolveDiffBase(task, cwd, headRef = "HEAD", runGit = runGitCommand) {
115346
+ const baseBranch = task.baseBranch ?? "main";
115347
+ let mergeBase;
115348
+ try {
115349
+ try {
115350
+ mergeBase = (await runGit(["merge-base", headRef, baseBranch], cwd, 5e3)).trim() || void 0;
115351
+ } catch {
115352
+ mergeBase = (await runGit(["merge-base", headRef, `origin/${baseBranch}`], cwd, 5e3)).trim() || void 0;
115353
+ }
115354
+ } catch {
115355
+ }
115356
+ if (mergeBase) {
115357
+ try {
115358
+ const head = (await runGit(["rev-parse", headRef], cwd, 5e3)).trim();
115359
+ if (head && head !== mergeBase) return mergeBase;
115360
+ } catch {
115361
+ return mergeBase;
115362
+ }
115363
+ }
115364
+ if (task.baseCommitSha) {
115365
+ try {
115366
+ await runGit(["merge-base", "--is-ancestor", task.baseCommitSha, headRef], cwd, 5e3);
115367
+ return task.baseCommitSha;
115368
+ } catch {
115369
+ }
115370
+ }
115371
+ try {
115372
+ return (await runGit(["rev-parse", `${headRef}~1`], cwd, 5e3)).trim() || void 0;
115373
+ } catch {
115374
+ return void 0;
115375
+ }
115376
+ }
115280
115377
  function slugifyPresetName(name) {
115281
115378
  const slug = name.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/-+/g, "-").replace(/^[-_]+|[-_]+$/g, "").slice(0, 32);
115282
115379
  return slug || "preset";
@@ -118110,38 +118207,6 @@ function createApiRoutes(store, options) {
118110
118207
  }
118111
118208
  }
118112
118209
  });
118113
- async function resolveDiffBase(task, cwd) {
118114
- const baseBranch = task.baseBranch ?? "main";
118115
- let mergeBase;
118116
- try {
118117
- try {
118118
- mergeBase = (await runGitCommand(["merge-base", "HEAD", baseBranch], cwd, 5e3)).trim() || void 0;
118119
- } catch {
118120
- mergeBase = (await runGitCommand(["merge-base", "HEAD", `origin/${baseBranch}`], cwd, 5e3)).trim() || void 0;
118121
- }
118122
- } catch {
118123
- }
118124
- if (mergeBase) {
118125
- try {
118126
- const head = (await runGitCommand(["rev-parse", "HEAD"], cwd, 5e3)).trim();
118127
- if (head && head !== mergeBase) return mergeBase;
118128
- } catch {
118129
- return mergeBase;
118130
- }
118131
- }
118132
- if (task.baseCommitSha) {
118133
- try {
118134
- await runGitCommand(["merge-base", "--is-ancestor", task.baseCommitSha, "HEAD"], cwd, 5e3);
118135
- return task.baseCommitSha;
118136
- } catch {
118137
- }
118138
- }
118139
- try {
118140
- return (await runGitCommand(["rev-parse", "HEAD~1"], cwd, 5e3)).trim() || void 0;
118141
- } catch {
118142
- return void 0;
118143
- }
118144
- }
118145
118210
  router.get("/tasks/:id/session-files", async (req, res) => {
118146
118211
  try {
118147
118212
  const { store: scopedStore } = await getProjectContext2(req);
@@ -136701,7 +136766,11 @@ function StatsPanel({ state, isFocused }) {
136701
136766
  /* @__PURE__ */ jsx(Text, { color: sysMemColor(sys.systemTotalMem - sys.systemFreeMem, sys.systemTotalMem), children: formatBytes2(sys.systemTotalMem - sys.systemFreeMem) }),
136702
136767
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "used" }),
136703
136768
  /* @__PURE__ */ jsx(Text, { children: formatBytes2(sys.systemFreeMem) }),
136704
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "free" })
136769
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "free" }),
136770
+ sys.systemTotalMem > 0 && /* @__PURE__ */ jsxs(Text, { color: sysMemColor(sys.systemTotalMem - sys.systemFreeMem, sys.systemTotalMem), children: [
136771
+ ((sys.systemTotalMem - sys.systemFreeMem) / sys.systemTotalMem * 100).toFixed(1),
136772
+ "%"
136773
+ ] })
136705
136774
  ] }),
136706
136775
  /* @__PURE__ */ jsxs(StatRow, { label: "Cores", children: [
136707
136776
  /* @__PURE__ */ jsx(Text, { children: sys.cpuCount }),
@@ -136860,14 +136929,19 @@ function ExpandedLog({ entry, index: index2, total }) {
136860
136929
  /* @__PURE__ */ jsx(Text, { wrap: "wrap", children: entry.message })
136861
136930
  ] });
136862
136931
  }
136863
- function UtilitiesPanel({ isFocused }) {
136932
+ function UtilitiesPanel({ state, isFocused }) {
136933
+ const autoKill = state.autoKillVitestOnPressure;
136934
+ const thresholdPct = Math.round(state.vitestKillThreshold * 100);
136864
136935
  const actions = [
136865
136936
  { key: "r", label: "Refresh Stats" },
136866
136937
  { key: "c", label: "Clear Logs" },
136867
136938
  { key: "t", label: "Toggle Engine Pause" },
136939
+ { key: "k", label: "Kill Vitest Processes" },
136940
+ { key: "v", label: `Auto-Kill Vitest >${thresholdPct}% Mem: ${autoKill ? "ON" : "OFF"}` },
136941
+ { key: "+/-", label: `Adjust Threshold (${thresholdPct}%)` },
136868
136942
  { key: "?", label: "Help" }
136869
136943
  ];
136870
- return /* @__PURE__ */ jsx(Panel, { title: "Utilities", isFocused, flexShrink: 0, children: /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: actions.map((action) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
136944
+ return /* @__PURE__ */ jsx(Panel, { title: "Utilities", isFocused, flexGrow: 1, children: /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: actions.map((action) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
136871
136945
  /* @__PURE__ */ jsxs(Text, { color: "yellow", children: [
136872
136946
  "[",
136873
136947
  action.key,
@@ -136892,6 +136966,9 @@ function HelpOverlay() {
136892
136966
  ["[\u2190] / [p]", "Previous panel (Main)"],
136893
136967
  ["[r]", "Refresh stats (Utilities)"],
136894
136968
  ["[c]", "Clear logs (Utilities)"],
136969
+ ["[k]", "Kill all vitest processes (Utilities)"],
136970
+ ["[v]", "Toggle auto-kill vitest on memory pressure (Utilities)"],
136971
+ ["[+/-]", "Adjust vitest kill memory threshold (Utilities)"],
136895
136972
  ["[\u2191/\u2193/k/j]", "Navigate list / log entries"],
136896
136973
  ["[Home / G]", "First / last log entry (Logs)"],
136897
136974
  ["[Enter/Space]", "Expand log entry (Logs)"],
@@ -136950,7 +137027,7 @@ function StatusModeGrid({
136950
137027
  }
136951
137028
  ),
136952
137029
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", overflow: "hidden", children: [
136953
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx(UtilitiesPanel, { isFocused: focused === "utilities" }) }),
137030
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx(UtilitiesPanel, { state, isFocused: focused === "utilities" }) }),
136954
137031
  /* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx(SettingsPanel, { state, isFocused: focused === "settings" }) })
136955
137032
  ] })
136956
137033
  ] })
@@ -136970,7 +137047,7 @@ function StatusModeSingle({
136970
137047
  case "logs":
136971
137048
  return /* @__PURE__ */ jsx(LogsPanel, { state, isFocused: true, availableRows: Math.max(4, (process.stdout.rows ?? 24) - 8) });
136972
137049
  case "utilities":
136973
- return /* @__PURE__ */ jsx(UtilitiesPanel, { isFocused: true });
137050
+ return /* @__PURE__ */ jsx(UtilitiesPanel, { state, isFocused: true });
136974
137051
  case "stats":
136975
137052
  return /* @__PURE__ */ jsx(StatsPanel, { state, isFocused: true });
136976
137053
  case "settings":
@@ -136989,7 +137066,7 @@ function StatusBar({ state, controller: _controller }) {
136989
137066
  if (activeSection === "logs") {
136990
137067
  hotkeys.push("\u2191\u2193 navigate", "w wrap", "f filter", "Enter expand");
136991
137068
  } else if (activeSection === "utilities") {
136992
- hotkeys.push("r refresh", "c clear logs", "t toggle pause");
137069
+ hotkeys.push("r refresh", "c clear logs", "t toggle pause", "k kill vitest", "v auto-kill", "+/- threshold");
136993
137070
  } else {
136994
137071
  hotkeys.push("Tab cycle panel", "1-5 jump");
136995
137072
  }
@@ -136998,9 +137075,9 @@ function StatusBar({ state, controller: _controller }) {
136998
137075
  statusParts.push(systemInfo.baseUrl);
136999
137076
  statusParts.push(formatUptime(Date.now() - systemInfo.startTimeMs));
137000
137077
  }
137001
- return /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", paddingX: 1, children: [
137002
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: hotkeys.join(" \xB7 ") }),
137003
- statusParts.length > 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: statusParts.join(" | ") })
137078
+ return /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", paddingX: 1, flexShrink: 0, children: [
137079
+ /* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate-end", children: hotkeys.join(" \xB7 ") }),
137080
+ statusParts.length > 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, wrap: "truncate-end", children: statusParts.join(" | ") })
137004
137081
  ] });
137005
137082
  }
137006
137083
  function MainHeader({ state }) {
@@ -137023,12 +137100,12 @@ function MainHeader({ state }) {
137023
137100
  const isActive = (t) => t.kind === "main" ? !inInteractive : inInteractive && t.view === interactiveView;
137024
137101
  if (tiny) {
137025
137102
  const active = tabs.find(isActive);
137026
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, paddingX: 1, children: [
137103
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, paddingX: 1, flexShrink: 0, overflow: "hidden", children: [
137027
137104
  /* @__PURE__ */ jsx(MiniLogo, {}),
137028
137105
  active && /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { backgroundColor: "cyan", color: "black", bold: true, children: ` ${active.key} ${active.label} ` }) })
137029
137106
  ] });
137030
137107
  }
137031
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, paddingX: 1, paddingY: 0, children: [
137108
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, paddingX: 1, paddingY: 0, flexShrink: 0, overflow: "hidden", children: [
137032
137109
  /* @__PURE__ */ jsx(MiniLogo, {}),
137033
137110
  /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2502" }) }),
137034
137111
  tabs.map((t) => {
@@ -139066,6 +139143,15 @@ function InteractiveMode({ state, controller }) {
139066
139143
  function DashboardApp({ controller }) {
139067
139144
  const { exit } = useApp();
139068
139145
  const { stdout } = useStdout();
139146
+ const [, setResizeTick] = useState2(0);
139147
+ useEffect2(() => {
139148
+ if (!stdout) return;
139149
+ const onResize = () => setResizeTick((t) => t + 1);
139150
+ stdout.on("resize", onResize);
139151
+ return () => {
139152
+ stdout.off("resize", onResize);
139153
+ };
139154
+ }, [stdout]);
139069
139155
  const cols = stdout?.columns ?? 80;
139070
139156
  const rows = stdout?.rows ?? 24;
139071
139157
  const state = useSyncExternalStore(
@@ -139216,14 +139302,15 @@ function DashboardApp({ controller }) {
139216
139302
  }
139217
139303
  }
139218
139304
  });
139305
+ const layoutKey = `${cols}x${rows}`;
139219
139306
  if (!state.systemInfo) {
139220
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", height: rows, children: /* @__PURE__ */ jsx(SplashScreen, { loadingStatus: state.loadingStatus }) });
139307
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", height: rows, width: cols, overflow: "hidden", children: /* @__PURE__ */ jsx(SplashScreen, { loadingStatus: state.loadingStatus }) }, layoutKey);
139221
139308
  }
139222
139309
  const isNarrow = cols < 80 || rows < 20;
139223
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: rows, children: [
139310
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height: rows, width: cols, overflow: "hidden", children: [
139224
139311
  state.mode === "interactive" ? /* @__PURE__ */ jsx(InteractiveMode, { state, controller }) : isNarrow ? /* @__PURE__ */ jsx(StatusModeSingle, { state, controller }) : /* @__PURE__ */ jsx(StatusModeGrid, { state, rows, controller }),
139225
139312
  state.showHelp && /* @__PURE__ */ jsx(Box, { position: "absolute", marginTop: 3, marginLeft: 4, children: /* @__PURE__ */ jsx(HelpOverlay, {}) })
139226
- ] });
139313
+ ] }, layoutKey);
139227
139314
  }
139228
139315
  var LOGO_COLORS, NARROW_THRESHOLD, SPLASH_MIN_COLS, SPLASH_MIN_ROWS, LARGE_LOGO_MIN_COLS, LARGE_LOGO_MIN_ROWS, PREFIX_WIDTH, PANEL_ORDER, KANBAN_COLUMNS, COLUMN_COLORS, STEP_ICON, STEP_COLOR, MAX_LOG_ENTRIES2, INITIAL_LOG_LIMIT, SETTING_DEFS, FILES_DENYLIST;
139229
139316
  var init_app = __esm({
@@ -139279,6 +139366,7 @@ var init_app = __esm({
139279
139366
  // src/commands/dashboard-tui/controller.ts
139280
139367
  import os3 from "node:os";
139281
139368
  import v8 from "node:v8";
139369
+ import { execSync as execSync2 } from "node:child_process";
139282
139370
  var DashboardTUI;
139283
139371
  var init_controller = __esm({
139284
139372
  "src/commands/dashboard-tui/controller.ts"() {
@@ -139309,6 +139397,15 @@ var init_controller = __esm({
139309
139397
  logsViewportStart = 0;
139310
139398
  loadingStatus = "Starting\u2026";
139311
139399
  mode = "status";
139400
+ // When true, sampleSystemStats() kills any running vitest processes if
139401
+ // system memory usage crosses 90%. Toggled by [v] in the Utilities panel.
139402
+ autoKillVitestOnPressure = true;
139403
+ // System-memory ratio (0..1) at which auto-kill triggers. Adjustable from
139404
+ // the Utilities panel via [+]/[-] in 5% steps. Clamped to [0.5, 0.99].
139405
+ vitestKillThreshold = 0.9;
139406
+ // Throttle so we don't spam kills while the sampler keeps firing during
139407
+ // sustained pressure (sampler runs every 2s).
139408
+ lastAutoKillAt = 0;
139312
139409
  interactiveData = null;
139313
139410
  interactiveView = "board";
139314
139411
  // Subscribers registered by the Ink App component.
@@ -139318,7 +139415,11 @@ var init_controller = __esm({
139318
139415
  // notify() invalidates this; getSnapshot() rebuilds on demand.
139319
139416
  cachedSnapshot = null;
139320
139417
  // Ink instance — set when start() is called.
139418
+ // Loose type — the real Ink Instance has additional methods (clear,
139419
+ // rerender, etc.) that we use defensively below.
139321
139420
  inkInstance = null;
139421
+ // Resize listener attached at start(), detached at stop().
139422
+ resizeListener = null;
139322
139423
  // Uptime ticker to keep footer time live.
139323
139424
  uptimeTimer = null;
139324
139425
  // System stats sampler — process memory + CPU%.
@@ -139352,7 +139453,9 @@ var init_controller = __esm({
139352
139453
  loadingStatus: this.loadingStatus,
139353
139454
  mode: this.mode,
139354
139455
  interactiveData: this.interactiveData,
139355
- interactiveView: this.interactiveView
139456
+ interactiveView: this.interactiveView,
139457
+ autoKillVitestOnPressure: this.autoKillVitestOnPressure,
139458
+ vitestKillThreshold: this.vitestKillThreshold
139356
139459
  };
139357
139460
  return this.cachedSnapshot;
139358
139461
  }
@@ -139425,6 +139528,82 @@ var init_controller = __esm({
139425
139528
  nodeVersion: process.version,
139426
139529
  platform: `${process.platform}/${process.arch}`
139427
139530
  });
139531
+ if (this.autoKillVitestOnPressure) {
139532
+ const total = os3.totalmem();
139533
+ const free = os3.freemem();
139534
+ if (total > 0) {
139535
+ const usedRatio = (total - free) / total;
139536
+ if (usedRatio > this.vitestKillThreshold && now - this.lastAutoKillAt > 3e4) {
139537
+ this.lastAutoKillAt = now;
139538
+ const result = this.killVitestProcesses();
139539
+ if (result.killed > 0) {
139540
+ this.warn(
139541
+ `Auto-killed ${result.killed} vitest process${result.killed === 1 ? "" : "es"} (system memory at ${Math.round(usedRatio * 100)}%, threshold ${Math.round(this.vitestKillThreshold * 100)}%)`,
139542
+ "memory-guard"
139543
+ );
139544
+ }
139545
+ }
139546
+ }
139547
+ }
139548
+ }
139549
+ /**
139550
+ * Find and SIGKILL any running vitest processes, excluding this dashboard
139551
+ * itself. Returns a count of pids signalled (best-effort — a pid may be
139552
+ * gone by the time we send the signal).
139553
+ */
139554
+ killVitestProcesses() {
139555
+ const selfPid = process.pid;
139556
+ let pids = [];
139557
+ try {
139558
+ const out = execSync2("pgrep -f vitest", { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
139559
+ pids = out.split("\n").map((s) => Number.parseInt(s.trim(), 10)).filter((n) => Number.isFinite(n) && n > 0 && n !== selfPid);
139560
+ } catch {
139561
+ return { killed: 0, pids: [] };
139562
+ }
139563
+ let killed = 0;
139564
+ for (const pid of pids) {
139565
+ try {
139566
+ process.kill(pid, "SIGKILL");
139567
+ killed += 1;
139568
+ } catch {
139569
+ }
139570
+ }
139571
+ return { killed, pids };
139572
+ }
139573
+ adjustVitestKillThreshold(deltaPct) {
139574
+ const next = this.vitestKillThreshold + deltaPct / 100;
139575
+ this.vitestKillThreshold = Math.max(0.5, Math.min(0.99, Math.round(next * 100) / 100));
139576
+ this.notify();
139577
+ void this.persistVitestKillSettings({ thresholdPct: Math.round(this.vitestKillThreshold * 100) });
139578
+ return this.vitestKillThreshold;
139579
+ }
139580
+ toggleAutoKillVitest() {
139581
+ this.autoKillVitestOnPressure = !this.autoKillVitestOnPressure;
139582
+ if (!this.autoKillVitestOnPressure) {
139583
+ this.lastAutoKillAt = 0;
139584
+ }
139585
+ this.notify();
139586
+ void this.persistVitestKillSettings({ enabled: this.autoKillVitestOnPressure });
139587
+ return this.autoKillVitestOnPressure;
139588
+ }
139589
+ /** Apply persisted values from global settings on startup. Does not
139590
+ * trigger a write-back. */
139591
+ hydrateVitestKillSettings(values) {
139592
+ if (typeof values.enabled === "boolean") {
139593
+ this.autoKillVitestOnPressure = values.enabled;
139594
+ }
139595
+ if (typeof values.thresholdPct === "number" && Number.isFinite(values.thresholdPct)) {
139596
+ const ratio = values.thresholdPct / 100;
139597
+ this.vitestKillThreshold = Math.max(0.5, Math.min(0.99, ratio));
139598
+ }
139599
+ this.notify();
139600
+ }
139601
+ async persistVitestKillSettings(partial) {
139602
+ if (!this.callbacks?.onPersistVitestKillSettings) return;
139603
+ try {
139604
+ await this.callbacks.onPersistVitestKillSettings(partial);
139605
+ } catch {
139606
+ }
139428
139607
  }
139429
139608
  setSettings(settings) {
139430
139609
  this.settings = settings;
@@ -139538,6 +139717,38 @@ var init_controller = __esm({
139538
139717
  this.setSettings(newSettings);
139539
139718
  }
139540
139719
  break;
139720
+ case "k": {
139721
+ const result = this.killVitestProcesses();
139722
+ if (result.killed === 0) {
139723
+ this.log("No vitest processes found.", "kill-vitest");
139724
+ } else {
139725
+ this.warn(
139726
+ `Killed ${result.killed} vitest process${result.killed === 1 ? "" : "es"}: ${result.pids.join(", ")}`,
139727
+ "kill-vitest"
139728
+ );
139729
+ }
139730
+ break;
139731
+ }
139732
+ case "v": {
139733
+ const enabled = this.toggleAutoKillVitest();
139734
+ this.log(
139735
+ `Auto-kill vitest on memory pressure (>${Math.round(this.vitestKillThreshold * 100)}%): ${enabled ? "ON" : "OFF"}`,
139736
+ "memory-guard"
139737
+ );
139738
+ break;
139739
+ }
139740
+ case "+":
139741
+ case "=": {
139742
+ const v = this.adjustVitestKillThreshold(5);
139743
+ this.log(`Vitest kill threshold: ${Math.round(v * 100)}%`, "memory-guard");
139744
+ break;
139745
+ }
139746
+ case "-":
139747
+ case "_": {
139748
+ const v = this.adjustVitestKillThreshold(-5);
139749
+ this.log(`Vitest kill threshold: ${Math.round(v * 100)}%`, "memory-guard");
139750
+ break;
139751
+ }
139541
139752
  }
139542
139753
  }
139543
139754
  // ── Lifecycle ──────────────────────────────────────────────────────────────
@@ -139547,9 +139758,21 @@ var init_controller = __esm({
139547
139758
  const { render } = await import("ink");
139548
139759
  const { createElement } = await import("react");
139549
139760
  const { DashboardApp: DashboardApp2 } = await Promise.resolve().then(() => (init_app(), app_exports));
139761
+ if (process.stdout?.isTTY && typeof process.stdout.write === "function") {
139762
+ process.stdout.write("\x1B[?1049h\x1B[H");
139763
+ }
139550
139764
  this.inkInstance = render(
139551
139765
  createElement(DashboardApp2, { controller: this })
139552
139766
  );
139767
+ this.resizeListener = () => {
139768
+ try {
139769
+ this.inkInstance?.clear?.();
139770
+ } catch {
139771
+ }
139772
+ };
139773
+ if (process.stdout && typeof process.stdout.on === "function") {
139774
+ process.stdout.on("resize", this.resizeListener);
139775
+ }
139553
139776
  this.uptimeTimer = setInterval(() => {
139554
139777
  if (this.isRunning) this.notify();
139555
139778
  }, 5e3);
@@ -139571,10 +139794,17 @@ var init_controller = __esm({
139571
139794
  clearInterval(this.systemStatsTimer);
139572
139795
  this.systemStatsTimer = null;
139573
139796
  }
139797
+ if (this.resizeListener && process.stdout && typeof process.stdout.off === "function") {
139798
+ process.stdout.off("resize", this.resizeListener);
139799
+ this.resizeListener = null;
139800
+ }
139574
139801
  if (this.inkInstance) {
139575
139802
  this.inkInstance.unmount();
139576
139803
  this.inkInstance = null;
139577
139804
  }
139805
+ if (process.stdout?.isTTY && typeof process.stdout.write === "function") {
139806
+ process.stdout.write("\x1B[?1049l");
139807
+ }
139578
139808
  }
139579
139809
  // ── Private helpers ────────────────────────────────────────────────────────
139580
139810
  clampSelectedLogIndex(entries) {
@@ -140191,6 +140421,18 @@ async function runDashboard(port, opts = {}) {
140191
140421
  enginePaused: paused,
140192
140422
  globalPause: false
140193
140423
  };
140424
+ },
140425
+ onPersistVitestKillSettings: async (partial) => {
140426
+ if (!store) return;
140427
+ const patch = {};
140428
+ if (typeof partial.enabled === "boolean") {
140429
+ patch.vitestAutoKillEnabled = partial.enabled;
140430
+ }
140431
+ if (typeof partial.thresholdPct === "number") {
140432
+ patch.vitestKillThresholdPct = partial.thresholdPct;
140433
+ }
140434
+ if (Object.keys(patch).length === 0) return;
140435
+ await store.getGlobalSettingsStore().updateSettings(patch);
140194
140436
  }
140195
140437
  });
140196
140438
  await tui.start();
@@ -140927,6 +141169,14 @@ async function runDashboard(port, opts = {}) {
140927
141169
  enginePaused: settings.enginePaused ?? false,
140928
141170
  globalPause: settings.globalPause ?? false
140929
141171
  });
141172
+ try {
141173
+ const globalSettings = await store.getGlobalSettingsStore().getSettings();
141174
+ tui.hydrateVitestKillSettings({
141175
+ enabled: typeof globalSettings.vitestAutoKillEnabled === "boolean" ? globalSettings.vitestAutoKillEnabled : void 0,
141176
+ thresholdPct: typeof globalSettings.vitestKillThresholdPct === "number" ? globalSettings.vitestKillThresholdPct : void 0
141177
+ });
141178
+ } catch {
141179
+ }
140930
141180
  const tasks = await store.listTasks({ slim: true, includeArchived: false });
140931
141181
  const counts = /* @__PURE__ */ new Map();
140932
141182
  for (const task of tasks) {
@@ -147419,6 +147669,7 @@ import { existsSync as existsSync47, mkdtempSync as mkdtempSync2, readFileSync a
147419
147669
  import { createRequire as createRequire4 } from "node:module";
147420
147670
  import { join as join59, dirname as dirname24 } from "node:path";
147421
147671
  import { tmpdir as tmpdir4 } from "node:os";
147672
+ import { performance as performance3 } from "node:perf_hooks";
147422
147673
  var isBunBinary3 = typeof Bun !== "undefined" && !!Bun.embeddedFiles;
147423
147674
  function configurePiPackage() {
147424
147675
  if (process.env.PI_PACKAGE_DIR) {
@@ -147451,6 +147702,10 @@ function configurePiPackage() {
147451
147702
  process.env.PI_PACKAGE_DIR = tmp;
147452
147703
  }
147453
147704
  configurePiPackage();
147705
+ setInterval(() => {
147706
+ performance3.clearMeasures();
147707
+ performance3.clearMarks();
147708
+ }, 3e4).unref();
147454
147709
  function loadEnvFile(path4) {
147455
147710
  if (!existsSync47(path4)) return;
147456
147711
  const contents = readFileSync17(path4, "utf-8");
@@ -1,4 +1,4 @@
1
- import{r as a,j as e}from"./vendor-react-K0fH_qHe.js";import{c as xe,c2 as ks,c3 as Cs,c4 as ws,c5 as Rs,L as O,R as ze,af as ts,Z as Ms,ah as Te,I as Ce,K as hs,D as gs,c6 as Fs,c7 as Ts,c8 as As,c9 as Ls,p as W,ca as Ds,s as as,B as ns,E as Ne,J as is,aK as ge,X as zs,F as we,A as Se,v as Ee,cb as Es,b_ as $s,ar as Ps,b5 as Bs,ai as fs,M as Is,U as Os,W as _s,cc as Le,cd as Hs,y as Vs,ce as Us,cf as Js,cg as Ws,ch as qs,ci as Gs,cj as $e,a3 as Pe,a5 as Be,a6 as Ie,C as X,a1 as Ks,ck as Ys,cl as Zs,i as Qs,h as Xs,j as et,cm as De,V as st,cn as tt,co as at,cp as nt,cq as it,cr as rt,cs as lt,ct as ot,cu as ct,Q as dt,cv as ut,N as mt}from"./index-CikysL-d.js";import{S as ht}from"./AgentsView-CWFLMIDP.js";import"./vendor-xterm-DzcZoU0P.js";import"./upload-BDvpReDO.js";import"./folder-open-BVDq27HP.js";/**
1
+ import{r as a,j as e}from"./vendor-react-K0fH_qHe.js";import{c as xe,c2 as ks,c3 as Cs,c4 as ws,c5 as Rs,L as O,R as ze,af as ts,Z as Ms,ah as Te,I as Ce,K as hs,D as gs,c6 as Fs,c7 as Ts,c8 as As,c9 as Ls,p as W,ca as Ds,s as as,B as ns,E as Ne,J as is,aK as ge,X as zs,F as we,A as Se,v as Ee,cb as Es,b_ as $s,ar as Ps,b5 as Bs,ai as fs,M as Is,U as Os,W as _s,cc as Le,cd as Hs,y as Vs,ce as Us,cf as Js,cg as Ws,ch as qs,ci as Gs,cj as $e,a3 as Pe,a5 as Be,a6 as Ie,C as X,a1 as Ks,ck as Ys,cl as Zs,i as Qs,h as Xs,j as et,cm as De,V as st,cn as tt,co as at,cp as nt,cq as it,cr as rt,cs as lt,ct as ot,cu as ct,Q as dt,cv as ut,N as mt}from"./index-CHoVMPAA.js";import{S as ht}from"./AgentsView-DPlnCa_B.js";import"./vendor-xterm-DzcZoU0P.js";import"./upload-B_grq4hM.js";import"./folder-open-J7yPbaCt.js";/**
2
2
  * @license lucide-react v1.7.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.