@runfusion/fusion 0.2.5 → 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 +269 -47
  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,11 +136929,16 @@ 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
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: [
@@ -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
  }
@@ -139289,6 +139366,7 @@ var init_app = __esm({
139289
139366
  // src/commands/dashboard-tui/controller.ts
139290
139367
  import os3 from "node:os";
139291
139368
  import v8 from "node:v8";
139369
+ import { execSync as execSync2 } from "node:child_process";
139292
139370
  var DashboardTUI;
139293
139371
  var init_controller = __esm({
139294
139372
  "src/commands/dashboard-tui/controller.ts"() {
@@ -139319,6 +139397,15 @@ var init_controller = __esm({
139319
139397
  logsViewportStart = 0;
139320
139398
  loadingStatus = "Starting\u2026";
139321
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;
139322
139409
  interactiveData = null;
139323
139410
  interactiveView = "board";
139324
139411
  // Subscribers registered by the Ink App component.
@@ -139366,7 +139453,9 @@ var init_controller = __esm({
139366
139453
  loadingStatus: this.loadingStatus,
139367
139454
  mode: this.mode,
139368
139455
  interactiveData: this.interactiveData,
139369
- interactiveView: this.interactiveView
139456
+ interactiveView: this.interactiveView,
139457
+ autoKillVitestOnPressure: this.autoKillVitestOnPressure,
139458
+ vitestKillThreshold: this.vitestKillThreshold
139370
139459
  };
139371
139460
  return this.cachedSnapshot;
139372
139461
  }
@@ -139439,6 +139528,82 @@ var init_controller = __esm({
139439
139528
  nodeVersion: process.version,
139440
139529
  platform: `${process.platform}/${process.arch}`
139441
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
+ }
139442
139607
  }
139443
139608
  setSettings(settings) {
139444
139609
  this.settings = settings;
@@ -139552,6 +139717,38 @@ var init_controller = __esm({
139552
139717
  this.setSettings(newSettings);
139553
139718
  }
139554
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
+ }
139555
139752
  }
139556
139753
  }
139557
139754
  // ── Lifecycle ──────────────────────────────────────────────────────────────
@@ -140224,6 +140421,18 @@ async function runDashboard(port, opts = {}) {
140224
140421
  enginePaused: paused,
140225
140422
  globalPause: false
140226
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);
140227
140436
  }
140228
140437
  });
140229
140438
  await tui.start();
@@ -140960,6 +141169,14 @@ async function runDashboard(port, opts = {}) {
140960
141169
  enginePaused: settings.enginePaused ?? false,
140961
141170
  globalPause: settings.globalPause ?? false
140962
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
+ }
140963
141180
  const tasks = await store.listTasks({ slim: true, includeArchived: false });
140964
141181
  const counts = /* @__PURE__ */ new Map();
140965
141182
  for (const task of tasks) {
@@ -147452,6 +147669,7 @@ import { existsSync as existsSync47, mkdtempSync as mkdtempSync2, readFileSync a
147452
147669
  import { createRequire as createRequire4 } from "node:module";
147453
147670
  import { join as join59, dirname as dirname24 } from "node:path";
147454
147671
  import { tmpdir as tmpdir4 } from "node:os";
147672
+ import { performance as performance3 } from "node:perf_hooks";
147455
147673
  var isBunBinary3 = typeof Bun !== "undefined" && !!Bun.embeddedFiles;
147456
147674
  function configurePiPackage() {
147457
147675
  if (process.env.PI_PACKAGE_DIR) {
@@ -147484,6 +147702,10 @@ function configurePiPackage() {
147484
147702
  process.env.PI_PACKAGE_DIR = tmp;
147485
147703
  }
147486
147704
  configurePiPackage();
147705
+ setInterval(() => {
147706
+ performance3.clearMeasures();
147707
+ performance3.clearMarks();
147708
+ }, 3e4).unref();
147487
147709
  function loadEnvFile(path4) {
147488
147710
  if (!existsSync47(path4)) return;
147489
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.