@runfusion/fusion 0.14.3 → 0.15.0

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 (34) hide show
  1. package/dist/bin.js +210 -71
  2. package/dist/client/assets/{AgentDetailView-BBCnqhqI.js → AgentDetailView-B1zViykq.js} +1 -1
  3. package/dist/client/assets/{AgentsView-BY-Yq-Te.js → AgentsView-Bl9JH5C8.js} +3 -3
  4. package/dist/client/assets/{ChatView-DkoJNxFW.js → ChatView-liNErE53.js} +1 -1
  5. package/dist/client/assets/{DevServerView-qvs6pp6c.js → DevServerView-CV_PpbnZ.js} +1 -1
  6. package/dist/client/assets/{DirectoryPicker-BkAIXNrP.js → DirectoryPicker-DPfkGnj5.js} +1 -1
  7. package/dist/client/assets/{DocumentsView-BcaUGgaL.js → DocumentsView-CESb6RI7.js} +1 -1
  8. package/dist/client/assets/{InsightsView-Dz9Ivclw.js → InsightsView-BKhvyEyQ.js} +1 -1
  9. package/dist/client/assets/{MemoryView-BsweARBT.js → MemoryView-DB-l2miV.js} +1 -1
  10. package/dist/client/assets/{NodesView-bAU-v4bJ.js → NodesView-DgTXO8mm.js} +1 -1
  11. package/dist/client/assets/{PiExtensionsManager-C_U2g7y3.js → PiExtensionsManager-C4fTzemh.js} +1 -1
  12. package/dist/client/assets/{PluginManager-pIDsTk5v.js → PluginManager-C2-dExUL.js} +1 -1
  13. package/dist/client/assets/{ResearchView-D4Eib_uR.js → ResearchView-CkVwRDVA.js} +1 -1
  14. package/dist/client/assets/{RoadmapsView-BaGwsUGS.js → RoadmapsView-Cu85_XrQ.js} +1 -1
  15. package/dist/client/assets/{SettingsModal-BiZVi3cI.js → SettingsModal-BGnSAeqa.js} +1 -1
  16. package/dist/client/assets/{SettingsModal-CRyg643t.js → SettingsModal-C0DokcId.js} +3 -3
  17. package/dist/client/assets/{SetupWizardModal-BcIGBBpA.js → SetupWizardModal-C_d9clJp.js} +1 -1
  18. package/dist/client/assets/{SkillMultiselect-DPARHJeQ.js → SkillMultiselect-DwGWYZi6.js} +1 -1
  19. package/dist/client/assets/{SkillsView-Da_d_HPu.js → SkillsView-C096TB7i.js} +1 -1
  20. package/dist/client/assets/{TodoView-5rAeqYtV.js → TodoView-CUiAt2mR.js} +1 -1
  21. package/dist/client/assets/{folder-open-CgjcFqww.js → folder-open-CKivQd8c.js} +1 -1
  22. package/dist/client/assets/index-B4StE1qN.js +662 -0
  23. package/dist/client/assets/index-DYJk0WDc.css +1 -0
  24. package/dist/client/assets/{list-checks-C9YWtF7h.js → list-checks-B3oufblU.js} +1 -1
  25. package/dist/client/assets/{star-4nUh67-U.js → star-damu_EYz.js} +1 -1
  26. package/dist/client/assets/{upload-CEt5-Bnq.js → upload-uH6CHlEw.js} +1 -1
  27. package/dist/client/assets/{users-4I0JDmgO.js → users-CUySbfji.js} +1 -1
  28. package/dist/client/index.html +2 -2
  29. package/dist/client/version.json +1 -1
  30. package/dist/extension.js +204 -69
  31. package/dist/pi-claude-cli/package.json +1 -1
  32. package/package.json +1 -1
  33. package/dist/client/assets/index-D1gTSlYB.css +0 -1
  34. package/dist/client/assets/index-DoQ5ALYY.js +0 -662
package/dist/bin.js CHANGED
@@ -242,7 +242,8 @@ var init_settings_schema = __esm({
242
242
  maxPostReviewFixes: 1,
243
243
  maxSpawnedAgentsPerParent: 5,
244
244
  maxSpawnedAgentsGlobal: 20,
245
- maintenanceIntervalMs: 9e5,
245
+ // Run maintenance (including WAL checkpointing) every 5 minutes by default.
246
+ maintenanceIntervalMs: 3e5,
246
247
  autoArchiveDoneTasksEnabled: true,
247
248
  autoArchiveDoneAfterMs: 48 * 60 * 60 * 1e3,
248
249
  archiveAgentLogMode: "compact",
@@ -2653,6 +2654,7 @@ var init_sqlite_adapter = __esm({
2653
2654
  // ../core/src/db.ts
2654
2655
  import { isAbsolute, join as join2 } from "node:path";
2655
2656
  import { mkdirSync, existsSync } from "node:fs";
2657
+ import { spawnSync } from "node:child_process";
2656
2658
  function toJson(value) {
2657
2659
  if (value === void 0 || value === null) return "[]";
2658
2660
  if (Array.isArray(value) && value.length === 0) return "[]";
@@ -3284,11 +3286,14 @@ CREATE INDEX IF NOT EXISTS idxTodoItemsSortOrder ON todo_items(listId, sortOrder
3284
3286
  Database = class {
3285
3287
  db;
3286
3288
  dbPath;
3289
+ inMemory;
3290
+ corruptionDetected = false;
3287
3291
  /** Tracks transaction nesting depth for savepoint-based nested transactions. */
3288
3292
  transactionDepth = 0;
3289
3293
  _fts5Available;
3290
3294
  constructor(fusionDir, options) {
3291
3295
  const inMemory = options?.inMemory === true;
3296
+ this.inMemory = inMemory;
3292
3297
  this.dbPath = inMemory ? ":memory:" : join2(fusionDir, "fusion.db");
3293
3298
  if (!inMemory && !isAbsolute(fusionDir)) {
3294
3299
  throw new Error(`[fusion] Database constructor requires an absolute fusionDir path, got: ${fusionDir}`);
@@ -3310,8 +3315,13 @@ This means a caller passed a .fusion directory where a project root was expected
3310
3315
  }
3311
3316
  if (!inMemory) {
3312
3317
  this.db.exec("PRAGMA journal_mode = WAL");
3318
+ this.db.exec("PRAGMA busy_timeout = 5000");
3319
+ this.db.exec("PRAGMA synchronous = NORMAL");
3320
+ this.db.exec("PRAGMA wal_autocheckpoint = 100");
3321
+ this.db.exec("PRAGMA journal_size_limit = 4194304");
3322
+ } else {
3323
+ this.db.exec("PRAGMA busy_timeout = 5000");
3313
3324
  }
3314
- this.db.exec("PRAGMA busy_timeout = 5000");
3315
3325
  this.db.exec("PRAGMA foreign_keys = ON");
3316
3326
  this._fts5Available = probeFts5(this.db);
3317
3327
  }
@@ -3392,6 +3402,35 @@ This means a caller passed a .fusion directory where a project root was expected
3392
3402
  return false;
3393
3403
  }
3394
3404
  }
3405
+ integrityCheck() {
3406
+ if (this.inMemory) {
3407
+ return { ok: true };
3408
+ }
3409
+ const rows = this.db.prepare("PRAGMA integrity_check(100)").all();
3410
+ const errors = rows.map((row) => row.integrity_check).filter((value) => typeof value === "string" && value !== "ok");
3411
+ if (errors.length > 0) {
3412
+ return { ok: false, errors };
3413
+ }
3414
+ return { ok: true };
3415
+ }
3416
+ recoverDatabase(outputPath) {
3417
+ if (this.inMemory) {
3418
+ return false;
3419
+ }
3420
+ const recoveredSql = spawnSync("sqlite3", ["-cmd", ".recover main", this.dbPath], {
3421
+ encoding: "utf-8",
3422
+ maxBuffer: 50 * 1024 * 1024
3423
+ });
3424
+ if (recoveredSql.status !== 0 || !recoveredSql.stdout) {
3425
+ return false;
3426
+ }
3427
+ const rebuilt = spawnSync("sqlite3", [outputPath], {
3428
+ input: recoveredSql.stdout,
3429
+ encoding: "utf-8",
3430
+ maxBuffer: 50 * 1024 * 1024
3431
+ });
3432
+ return rebuilt.status === 0;
3433
+ }
3395
3434
  /**
3396
3435
  * Initialize the database: create tables if they don't exist
3397
3436
  * and seed meta values.
@@ -3410,6 +3449,11 @@ This means a caller passed a .fusion directory where a project root was expected
3410
3449
  this.db.exec(
3411
3450
  `INSERT OR IGNORE INTO config (id, nextId, nextWorkflowStepId, settings, workflowSteps, updatedAt) VALUES (1, 1, 1, '${JSON.stringify(DEFAULT_PROJECT_SETTINGS)}', '[]', '${configNow}')`
3412
3451
  );
3452
+ const integrity = this.integrityCheck();
3453
+ if (!integrity.ok) {
3454
+ this.corruptionDetected = true;
3455
+ console.warn("[fusion:db] Database integrity check FAILED \u2014 corruption detected");
3456
+ }
3413
3457
  }
3414
3458
  /**
3415
3459
  * Run incremental schema migrations based on the stored schema version.
@@ -19079,7 +19123,7 @@ __export(migration_exports, {
19079
19123
  MigrationCoordinator: () => MigrationCoordinator,
19080
19124
  ProjectRequiredError: () => ProjectRequiredError
19081
19125
  });
19082
- import { existsSync as existsSync9, readFileSync as readFileSync2 } from "node:fs";
19126
+ import { existsSync as existsSync9, readFileSync as readFileSync2, realpathSync as realpathSync2 } from "node:fs";
19083
19127
  import { homedir as homedir2, tmpdir } from "node:os";
19084
19128
  import { isAbsolute as isAbsolute3, join as join12, resolve as resolve5, basename as basename3, dirname as dirname4 } from "node:path";
19085
19129
  function getHomeDir2() {
@@ -19180,12 +19224,30 @@ var init_migration = __esm({
19180
19224
  const projects = [];
19181
19225
  const visited = /* @__PURE__ */ new Set();
19182
19226
  let current = resolve5(startDir);
19183
- const home = getHomeDir2();
19227
+ const home = resolve5(getHomeDir2());
19184
19228
  const root = dirname4(current) === current ? current : "/";
19185
19229
  const systemTmp = resolve5(tmpdir());
19186
- while (current !== home && current !== root && current !== systemTmp) {
19230
+ const normalizePath2 = (path5) => {
19231
+ try {
19232
+ return realpathSync2(path5);
19233
+ } catch {
19234
+ return resolve5(path5);
19235
+ }
19236
+ };
19237
+ const normalizedHome = normalizePath2(home);
19238
+ const normalizedSystemTmp = normalizePath2(systemTmp);
19239
+ const normalizedStartDir = normalizePath2(current);
19240
+ while (true) {
19187
19241
  if (visited.has(current)) break;
19188
19242
  visited.add(current);
19243
+ const normalizedCurrent = normalizePath2(current);
19244
+ const isRootBoundary = current === root;
19245
+ const isHomeBoundary = normalizedCurrent === normalizedHome;
19246
+ const isTmpBoundary = normalizedCurrent === normalizedSystemTmp;
19247
+ const isStopBoundary = isRootBoundary || isHomeBoundary || isTmpBoundary;
19248
+ if (isRootBoundary || isTmpBoundary || isHomeBoundary && normalizedCurrent !== normalizedStartDir) {
19249
+ break;
19250
+ }
19189
19251
  if (this.hasFusionProject(current)) {
19190
19252
  const name = await this.generateProjectName(current);
19191
19253
  projects.push({
@@ -19195,6 +19257,9 @@ var init_migration = __esm({
19195
19257
  });
19196
19258
  break;
19197
19259
  }
19260
+ if (isStopBoundary) {
19261
+ break;
19262
+ }
19198
19263
  const parent2 = dirname4(current);
19199
19264
  if (parent2 === current) break;
19200
19265
  current = parent2;
@@ -34503,6 +34568,39 @@ ${task.description}
34503
34568
  this.db.bumpLastModified();
34504
34569
  this.emit("agent:log", entry);
34505
34570
  }
34571
+ async appendAgentLogBatch(entries) {
34572
+ if (entries.length === 0) {
34573
+ return;
34574
+ }
34575
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
34576
+ const stmt = this.db.prepare(`
34577
+ INSERT INTO agentLogEntries (taskId, timestamp, text, type, detail, agent)
34578
+ VALUES (?, ?, ?, ?, ?, ?)
34579
+ `);
34580
+ this.db.transaction(() => {
34581
+ for (const entry of entries) {
34582
+ stmt.run(
34583
+ entry.taskId,
34584
+ timestamp,
34585
+ entry.text,
34586
+ entry.type,
34587
+ entry.detail ?? null,
34588
+ entry.agent ?? null
34589
+ );
34590
+ }
34591
+ });
34592
+ this.db.bumpLastModified();
34593
+ for (const entry of entries) {
34594
+ this.emit("agent:log", {
34595
+ timestamp,
34596
+ taskId: entry.taskId,
34597
+ text: entry.text,
34598
+ type: entry.type,
34599
+ ...entry.detail !== void 0 && { detail: entry.detail },
34600
+ ...entry.agent !== void 0 && { agent: entry.agent }
34601
+ });
34602
+ }
34603
+ }
34506
34604
  mapAgentLogRow(row) {
34507
34605
  return {
34508
34606
  timestamp: row.timestamp,
@@ -37492,6 +37590,20 @@ var init_plugin_loader = __esm({
37492
37590
  }
37493
37591
  return slots;
37494
37592
  }
37593
+ /**
37594
+ * Get all top-level dashboard view definitions from loaded plugins.
37595
+ */
37596
+ getPluginDashboardViews() {
37597
+ const views = [];
37598
+ for (const [pluginId, plugin4] of this.plugins) {
37599
+ if (plugin4.dashboardViews) {
37600
+ for (const view of plugin4.dashboardViews) {
37601
+ views.push({ pluginId, view });
37602
+ }
37603
+ }
37604
+ }
37605
+ return views;
37606
+ }
37495
37607
  /**
37496
37608
  * Get all runtime registrations from loaded plugins.
37497
37609
  * Returns plugin ownership metadata along with the runtime registration.
@@ -51987,18 +52099,21 @@ function summarizeToolArgs(name, args) {
51987
52099
  }
51988
52100
  return void 0;
51989
52101
  }
51990
- var FLUSH_SIZE_BYTES, FLUSH_INTERVAL_MS, AgentLogger;
52102
+ var FLUSH_SIZE_BYTES, FLUSH_INTERVAL_MS, ENTRY_BATCH_SIZE, AgentLogger;
51991
52103
  var init_agent_logger = __esm({
51992
52104
  "../engine/src/agent-logger.ts"() {
51993
52105
  "use strict";
51994
52106
  init_logger2();
51995
52107
  FLUSH_SIZE_BYTES = 1024;
51996
52108
  FLUSH_INTERVAL_MS = 500;
52109
+ ENTRY_BATCH_SIZE = 50;
51997
52110
  AgentLogger = class {
51998
52111
  textBuffer = "";
51999
52112
  thinkingBuffer = "";
52000
52113
  flushTimer = null;
52001
52114
  thinkingFlushTimer = null;
52115
+ entryFlushTimer = null;
52116
+ pendingEntries = [];
52002
52117
  flushSizeBytes;
52003
52118
  flushIntervalMs;
52004
52119
  store;
@@ -52103,8 +52218,13 @@ var init_agent_logger = __esm({
52103
52218
  clearTimeout(this.thinkingFlushTimer);
52104
52219
  this.thinkingFlushTimer = null;
52105
52220
  }
52221
+ if (this.entryFlushTimer) {
52222
+ clearTimeout(this.entryFlushTimer);
52223
+ this.entryFlushTimer = null;
52224
+ }
52106
52225
  await this.flushTextBuffer();
52107
52226
  await this.flushThinkingBuffer();
52227
+ await this.flushPendingEntries();
52108
52228
  }
52109
52229
  // ── Internal helpers ───────────────────────────────────────────────
52110
52230
  /**
@@ -52113,7 +52233,7 @@ var init_agent_logger = __esm({
52113
52233
  * When only `appendLogCb` is set (no store/taskId), only the callback is used.
52114
52234
  * @param storeWarnMsg - Warning message prefix used when the task-store write fails.
52115
52235
  */
52116
- writeEntry(text, type, detail, storeWarnMsg) {
52236
+ writeEntry(text, type, detail, _storeWarnMsg, immediate = false) {
52117
52237
  const entry = {
52118
52238
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
52119
52239
  taskId: this.taskId,
@@ -52122,72 +52242,38 @@ var init_agent_logger = __esm({
52122
52242
  ...detail !== void 0 && { detail },
52123
52243
  ...this.agent !== void 0 && { agent: this.agent }
52124
52244
  };
52125
- if (this.store && this.taskId) {
52126
- this.store.appendAgentLog(this.taskId, text, type, detail, this.agent).catch((err) => {
52127
- this.log.warn(`${storeWarnMsg}: ${err instanceof Error ? err.message : String(err)}`);
52128
- });
52245
+ this.pendingEntries.push(entry);
52246
+ if (immediate || type !== "text" && type !== "thinking") {
52247
+ if (this.entryFlushTimer) {
52248
+ clearTimeout(this.entryFlushTimer);
52249
+ this.entryFlushTimer = null;
52250
+ }
52251
+ void this.flushPendingEntries();
52252
+ return;
52129
52253
  }
52130
- if (this.appendLogCb) {
52131
- this.appendLogCb(entry).catch((err) => {
52132
- this.log.warn(`appendLog callback failed for entry (${type}): ${err instanceof Error ? err.message : String(err)}`);
52133
- });
52254
+ if (this.pendingEntries.length >= ENTRY_BATCH_SIZE) {
52255
+ if (this.entryFlushTimer) {
52256
+ clearTimeout(this.entryFlushTimer);
52257
+ this.entryFlushTimer = null;
52258
+ }
52259
+ void this.flushPendingEntries();
52260
+ return;
52134
52261
  }
52262
+ this.scheduleEntryFlush();
52135
52263
  }
52136
52264
  flushTextBuffer() {
52137
52265
  if (this.textBuffer.length === 0) return Promise.resolve();
52138
52266
  const chunk = this.textBuffer;
52139
52267
  this.textBuffer = "";
52140
- const entry = {
52141
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
52142
- taskId: this.taskId,
52143
- text: chunk,
52144
- type: "text",
52145
- ...this.agent !== void 0 && { agent: this.agent }
52146
- };
52147
- const promises = [];
52148
- if (this.store && this.taskId) {
52149
- promises.push(
52150
- this.store.appendAgentLog(this.taskId, chunk, "text", void 0, this.agent).catch((err) => {
52151
- this.log.warn(`Failed to flush text buffer for ${this.taskId}: ${err instanceof Error ? err.message : String(err)}`);
52152
- })
52153
- );
52154
- }
52155
- if (this.appendLogCb) {
52156
- promises.push(
52157
- this.appendLogCb(entry).catch((err) => {
52158
- this.log.warn(`appendLog callback failed for text flush: ${err instanceof Error ? err.message : String(err)}`);
52159
- })
52160
- );
52161
- }
52162
- return Promise.all(promises).then(() => void 0);
52268
+ this.writeEntry(chunk, "text", void 0, `Failed to flush text buffer for ${this.taskId}`, true);
52269
+ return this.flushPendingEntries();
52163
52270
  }
52164
52271
  flushThinkingBuffer() {
52165
52272
  if (this.thinkingBuffer.length === 0) return Promise.resolve();
52166
52273
  const chunk = this.thinkingBuffer;
52167
52274
  this.thinkingBuffer = "";
52168
- const entry = {
52169
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
52170
- taskId: this.taskId,
52171
- text: chunk,
52172
- type: "thinking",
52173
- ...this.agent !== void 0 && { agent: this.agent }
52174
- };
52175
- const promises = [];
52176
- if (this.store && this.taskId) {
52177
- promises.push(
52178
- this.store.appendAgentLog(this.taskId, chunk, "thinking", void 0, this.agent).catch((err) => {
52179
- this.log.warn(`Failed to flush thinking buffer for ${this.taskId}: ${err instanceof Error ? err.message : String(err)}`);
52180
- })
52181
- );
52182
- }
52183
- if (this.appendLogCb) {
52184
- promises.push(
52185
- this.appendLogCb(entry).catch((err) => {
52186
- this.log.warn(`appendLog callback failed for thinking flush: ${err instanceof Error ? err.message : String(err)}`);
52187
- })
52188
- );
52189
- }
52190
- return Promise.all(promises).then(() => void 0);
52275
+ this.writeEntry(chunk, "thinking", void 0, `Failed to flush thinking buffer for ${this.taskId}`, true);
52276
+ return this.flushPendingEntries();
52191
52277
  }
52192
52278
  scheduleFlush() {
52193
52279
  if (this.flushTimer) return;
@@ -52203,6 +52289,52 @@ var init_agent_logger = __esm({
52203
52289
  this.flushThinkingBuffer();
52204
52290
  }, this.flushIntervalMs);
52205
52291
  }
52292
+ scheduleEntryFlush() {
52293
+ if (this.entryFlushTimer) return;
52294
+ this.entryFlushTimer = setTimeout(() => {
52295
+ this.entryFlushTimer = null;
52296
+ void this.flushPendingEntries();
52297
+ }, this.flushIntervalMs);
52298
+ }
52299
+ async flushPendingEntries() {
52300
+ if (this.pendingEntries.length === 0) {
52301
+ return;
52302
+ }
52303
+ const entries = this.pendingEntries;
52304
+ this.pendingEntries = [];
52305
+ if (this.store && this.taskId) {
52306
+ if (typeof this.store.appendAgentLogBatch === "function") {
52307
+ await this.store.appendAgentLogBatch(
52308
+ entries.map((entry) => ({
52309
+ taskId: entry.taskId,
52310
+ text: entry.text,
52311
+ type: entry.type,
52312
+ detail: entry.detail,
52313
+ agent: entry.agent
52314
+ }))
52315
+ ).catch((err) => {
52316
+ this.log.warn(`Failed to flush agent log batch for ${this.taskId}: ${err instanceof Error ? err.message : String(err)}`);
52317
+ });
52318
+ } else {
52319
+ await Promise.all(
52320
+ entries.map(
52321
+ (entry) => this.store.appendAgentLog(entry.taskId, entry.text, entry.type, entry.detail, entry.agent).catch((err) => {
52322
+ this.log.warn(`Failed to flush agent log entry for ${this.taskId}: ${err instanceof Error ? err.message : String(err)}`);
52323
+ })
52324
+ )
52325
+ );
52326
+ }
52327
+ }
52328
+ if (this.appendLogCb) {
52329
+ await Promise.all(
52330
+ entries.map(
52331
+ (entry) => this.appendLogCb(entry).catch((err) => {
52332
+ this.log.warn(`appendLog callback failed for entry (${entry.type}): ${err instanceof Error ? err.message : String(err)}`);
52333
+ })
52334
+ )
52335
+ );
52336
+ }
52337
+ }
52206
52338
  };
52207
52339
  }
52208
52340
  });
@@ -89361,7 +89493,7 @@ var init_src3 = __esm({
89361
89493
  });
89362
89494
 
89363
89495
  // ../../plugins/fusion-plugin-hermes-runtime/dist/cli-spawn.js
89364
- import { spawn as spawn6, spawnSync } from "node:child_process";
89496
+ import { spawn as spawn6, spawnSync as spawnSync2 } from "node:child_process";
89365
89497
  import os2 from "node:os";
89366
89498
  import path, { sep as PATH_SEP } from "node:path";
89367
89499
  function resolveBinaryForSpawn(binary) {
@@ -89374,7 +89506,7 @@ function resolveBinaryForSpawn(binary) {
89374
89506
  if (cached)
89375
89507
  return cached;
89376
89508
  try {
89377
- const result = spawnSync("where", [binary], { encoding: "utf-8" });
89509
+ const result = spawnSync2("where", [binary], { encoding: "utf-8" });
89378
89510
  if (result.status === 0) {
89379
89511
  const first = (result.stdout ?? "").trim().split(/\r?\n/)[0];
89380
89512
  if (first?.length) {
@@ -124356,7 +124488,7 @@ var require_commonjs4 = __commonJS({
124356
124488
  var node_url_1 = __require("node:url");
124357
124489
  var fs_1 = __require("fs");
124358
124490
  var actualFS = __importStar(__require("node:fs"));
124359
- var realpathSync2 = fs_1.realpathSync.native;
124491
+ var realpathSync3 = fs_1.realpathSync.native;
124360
124492
  var promises_1 = __require("node:fs/promises");
124361
124493
  var minipass_1 = require_commonjs3();
124362
124494
  var defaultFS = {
@@ -124364,7 +124496,7 @@ var require_commonjs4 = __commonJS({
124364
124496
  readdir: fs_1.readdir,
124365
124497
  readdirSync: fs_1.readdirSync,
124366
124498
  readlinkSync: fs_1.readlinkSync,
124367
- realpathSync: realpathSync2,
124499
+ realpathSync: realpathSync3,
124368
124500
  promises: {
124369
124501
  lstat: promises_1.lstat,
124370
124502
  readdir: promises_1.readdir,
@@ -149887,6 +150019,10 @@ Description: ${step.description}`
149887
150019
  const slots = options?.pluginLoader?.getPluginUiSlots() ?? [];
149888
150020
  res.json(slots);
149889
150021
  });
150022
+ router.get("/plugins/dashboard-views", async (_req, res) => {
150023
+ const views = options?.pluginLoader?.getPluginDashboardViews() ?? [];
150024
+ res.json(views);
150025
+ });
149890
150026
  router.get("/plugins/runtimes", async (_req, res) => {
149891
150027
  const runtimes2 = options?.pluginLoader?.getPluginRuntimes() ?? [];
149892
150028
  const installed = runtimes2.map(({ pluginId, runtime }) => ({
@@ -158094,7 +158230,8 @@ async function clearDefaultProject(globalDir) {
158094
158230
  await globalStore.updateSettings(rest);
158095
158231
  }
158096
158232
  async function detectProjectFromCwd(cwd, central) {
158097
- let currentDir = resolve27(cwd);
158233
+ const startDir = resolve27(cwd);
158234
+ let currentDir = startDir;
158098
158235
  while (true) {
158099
158236
  const kbPath = resolve27(currentDir, ".fusion", "fusion.db");
158100
158237
  if (isValidSqliteDatabaseFile(kbPath)) {
@@ -158102,11 +158239,13 @@ async function detectProjectFromCwd(cwd, central) {
158102
158239
  if (project) {
158103
158240
  return project;
158104
158241
  }
158105
- return {
158106
- id: "",
158107
- name: basename16(currentDir) || "current-project",
158108
- path: currentDir
158109
- };
158242
+ if (currentDir === startDir) {
158243
+ return {
158244
+ id: "",
158245
+ name: basename16(currentDir) || "current-project",
158246
+ path: currentDir
158247
+ };
158248
+ }
158110
158249
  }
158111
158250
  const parentDir = dirname21(currentDir);
158112
158251
  if (parentDir === currentDir) {
@@ -1,4 +1,4 @@
1
- import{r as t,j as e}from"./vendor-react-K0fH_qHe.js";import{c as We,dk as Hs,dl as Is,dm as Os,dn as _s,L as O,R as Ye,al as hs,Z as Vs,am as Ue,V as Le,W as Ss,N as ks,dp as Us,dq as Js,dr as qs,w as Rs,cx as Gs,ds as Ws,z as q,dt as Ys,du as Cs,dv as ws,s as Ee,B as gs,Q as Ae,U as fs,a$ as ye,X as Ks,F as Se,A as Te,I as Ke,dw as Zs,cr as Qs,aF as Xs,bn as et,an as Ms,Y as st,a1 as tt,a3 as at,dx as qe,j as Fs,dy as nt,r as it,dz as rt,dA as lt,dB as ct,dC as De,a9 as Pe,ab as ze,ac as Be,C as X,a7 as As,dD as ot,dE as dt,i as ut,h as mt,k as ht,dF as Ge,a2 as gt,dG as ft,dH as xt,dI as pt,dJ as vt,dK as bt,dL as Es,dM as jt,dN as Nt,a0 as yt,dO as St,_ as kt,dP as Rt}from"./index-DoQ5ALYY.js";import{S as Ts}from"./star-4nUh67-U.js";import{S as Ct}from"./SkillMultiselect-DPARHJeQ.js";import{L as $s}from"./list-checks-C9YWtF7h.js";import"./vendor-xterm-DzcZoU0P.js";/**
1
+ import{r as t,j as e}from"./vendor-react-K0fH_qHe.js";import{c as We,dk as Hs,dl as Is,dm as Os,dn as _s,L as O,R as Ye,al as hs,Z as Vs,am as Ue,V as Le,W as Ss,N as ks,dp as Us,dq as Js,dr as qs,w as Rs,cx as Gs,ds as Ws,z as q,dt as Ys,du as Cs,dv as ws,s as Ee,B as gs,Q as Ae,U as fs,a$ as ye,X as Ks,F as Se,A as Te,I as Ke,dw as Zs,cr as Qs,aF as Xs,bn as et,an as Ms,Y as st,a1 as tt,a3 as at,dx as qe,j as Fs,dy as nt,r as it,dz as rt,dA as lt,dB as ct,dC as De,a9 as Pe,ab as ze,ac as Be,C as X,a7 as As,dD as ot,dE as dt,i as ut,h as mt,k as ht,dF as Ge,a2 as gt,dG as ft,dH as xt,dI as pt,dJ as vt,dK as bt,dL as Es,dM as jt,dN as Nt,a0 as yt,dO as St,_ as kt,dP as Rt}from"./index-B4StE1qN.js";import{S as Ts}from"./star-damu_EYz.js";import{S as Ct}from"./SkillMultiselect-DwGWYZi6.js";import{L as $s}from"./list-checks-B3oufblU.js";import"./vendor-xterm-DzcZoU0P.js";/**
2
2
  * @license lucide-react v1.7.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.