@runfusion/fusion 0.13.0 → 0.14.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 (69) hide show
  1. package/README.md +13 -0
  2. package/dist/bin.js +1250 -522
  3. package/dist/client/assets/AgentDetailView-CBFUveyO.js +18 -0
  4. package/dist/client/assets/{AgentsView-Dvf_xUkx.js → AgentsView-DPezXQ-U.js} +4 -4
  5. package/dist/client/assets/ChatView-5N4-EuhD.js +1 -0
  6. package/dist/client/assets/{DevServerView-C2qTJch7.js → DevServerView-Daft4YFc.js} +1 -1
  7. package/dist/client/assets/{DirectoryPicker-DRfhg9zz.js → DirectoryPicker-rew1y6qO.js} +1 -1
  8. package/dist/client/assets/{DocumentsView-j8ic1xUw.js → DocumentsView-i72qJzwd.js} +1 -1
  9. package/dist/client/assets/{InsightsView-CpAz3o0i.js → InsightsView-BL5eZJ0a.js} +1 -1
  10. package/dist/client/assets/{MemoryView-BcQsi_JK.js → MemoryView-pl8Cdg_p.js} +1 -1
  11. package/dist/client/assets/{NodesView-Bo_Yhr4N.js → NodesView-D6eJ15zc.js} +1 -1
  12. package/dist/client/assets/PiExtensionsManager-ExInwXWP.js +11 -0
  13. package/dist/client/assets/{PluginManager-BQhBHWrB.js → PluginManager-CYhtxHun.js} +1 -1
  14. package/dist/client/assets/{ResearchView-CLyyqAWE.js → ResearchView-B_QPUEjB.js} +1 -1
  15. package/dist/client/assets/{RoadmapsView-tG7IdOoc.js → RoadmapsView-DBNLaEsK.js} +1 -1
  16. package/dist/client/assets/SettingsModal-1ET586M3.js +31 -0
  17. package/dist/client/assets/{SettingsModal-CXUGeZ0_.js → SettingsModal-CL_gWmOj.js} +1 -1
  18. package/dist/client/assets/SettingsModal-D_AFkDJa.css +1 -0
  19. package/dist/client/assets/{SetupWizardModal-BMJL6eNR.js → SetupWizardModal-CLkY9HFL.js} +1 -1
  20. package/dist/client/assets/{SkillMultiselect-ILMft-Kz.js → SkillMultiselect-B0qi32SQ.js} +1 -1
  21. package/dist/client/assets/{SkillsView-x4_YwBz6.js → SkillsView-umVjRq6o.js} +1 -1
  22. package/dist/client/assets/TodoView-CFifSvrD.js +6 -0
  23. package/dist/client/assets/TodoView-SeO9o7km.css +1 -0
  24. package/dist/client/assets/{folder-open-DDdJt8aE.js → folder-open-nYPrL1W3.js} +1 -1
  25. package/dist/client/assets/index-Bc8nfKeH.js +661 -0
  26. package/dist/client/assets/index-C1prPuSl.css +1 -0
  27. package/dist/client/assets/{list-checks-DFxQ9biT.js → list-checks-sK8xJeH_.js} +1 -1
  28. package/dist/client/assets/{star-BKs1bgJN.js → star-BRtXbYkB.js} +1 -1
  29. package/dist/client/assets/{upload-Bb5Pidne.js → upload-BP60eBwN.js} +1 -1
  30. package/dist/client/assets/{users-BImNn91Q.js → users-qSGAX2Pf.js} +1 -1
  31. package/dist/client/index.html +2 -2
  32. package/dist/client/sw.js +6 -0
  33. package/dist/client/version.json +1 -1
  34. package/dist/droid-cli/index.ts +127 -0
  35. package/dist/droid-cli/package.json +37 -0
  36. package/dist/droid-cli/src/__tests__/control-handler.test.ts +164 -0
  37. package/dist/droid-cli/src/__tests__/event-bridge.test.ts +1318 -0
  38. package/dist/droid-cli/src/__tests__/mcp-config.test.ts +310 -0
  39. package/dist/droid-cli/src/__tests__/process-manager.test.ts +818 -0
  40. package/dist/droid-cli/src/__tests__/prompt-builder.test.ts +1206 -0
  41. package/dist/droid-cli/src/__tests__/provider.test.ts +1894 -0
  42. package/dist/droid-cli/src/__tests__/setup-test-isolation.test.ts +32 -0
  43. package/dist/droid-cli/src/__tests__/setup-test-isolation.ts +14 -0
  44. package/dist/droid-cli/src/__tests__/stream-parser.test.ts +188 -0
  45. package/dist/droid-cli/src/__tests__/thinking-config.test.ts +141 -0
  46. package/dist/droid-cli/src/__tests__/tool-mapping.test.ts +253 -0
  47. package/dist/droid-cli/src/control-handler.ts +82 -0
  48. package/dist/droid-cli/src/event-bridge.ts +397 -0
  49. package/dist/droid-cli/src/mcp-config.ts +144 -0
  50. package/dist/droid-cli/src/mcp-schema-server.cjs +49 -0
  51. package/dist/droid-cli/src/process-manager.ts +358 -0
  52. package/dist/droid-cli/src/prompt-builder.ts +629 -0
  53. package/dist/droid-cli/src/provider.ts +447 -0
  54. package/dist/droid-cli/src/stream-parser.ts +37 -0
  55. package/dist/droid-cli/src/thinking-config.ts +83 -0
  56. package/dist/droid-cli/src/tool-mapping.ts +147 -0
  57. package/dist/droid-cli/src/types.ts +87 -0
  58. package/dist/extension.js +473 -119
  59. package/dist/pi-claude-cli/package.json +1 -1
  60. package/package.json +2 -1
  61. package/dist/client/assets/AgentDetailView-B7j297GT.js +0 -18
  62. package/dist/client/assets/ChatView-BgUt38ty.js +0 -1
  63. package/dist/client/assets/PiExtensionsManager-DHt2zFg8.js +0 -11
  64. package/dist/client/assets/SettingsModal-9HS8MnmW.css +0 -1
  65. package/dist/client/assets/SettingsModal-UziTDnLh.js +0 -31
  66. package/dist/client/assets/TodoView-BBYcMbXE.js +0 -6
  67. package/dist/client/assets/TodoView-C1g65hJo.css +0 -1
  68. package/dist/client/assets/index-B15xwijw.css +0 -1
  69. package/dist/client/assets/index-DmSs2FGE.js +0 -661
package/dist/bin.js CHANGED
@@ -1009,11 +1009,40 @@ function hasAgentIdentity(agent) {
1009
1009
  if (!agent) return false;
1010
1010
  return !!(agent.soul?.trim() || agent.instructionsText?.trim() || agent.instructionsPath?.trim() || agent.memory?.trim());
1011
1011
  }
1012
- function getDefaultHeartbeatProcedurePath(agentId) {
1012
+ function slugifyAgentAssetSegment(value) {
1013
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1014
+ }
1015
+ function getSafeAgentAssetIdSegment(agentId) {
1016
+ const slug = slugifyAgentAssetSegment(agentId);
1017
+ return slug || "agent";
1018
+ }
1019
+ function getCanonicalAgentAssetDirectoryName(agentName, agentId) {
1020
+ if (!agentId || typeof agentId !== "string") {
1021
+ throw new Error("getCanonicalAgentAssetDirectoryName requires a non-empty agentId");
1022
+ }
1023
+ const safeId = getSafeAgentAssetIdSegment(agentId);
1024
+ const nameSlug = slugifyAgentAssetSegment(agentName ?? "");
1025
+ const prefix = nameSlug || safeId;
1026
+ return `${prefix}-${safeId}`;
1027
+ }
1028
+ function getLegacyAgentAssetDirectoryName(agentId) {
1029
+ if (!agentId || typeof agentId !== "string") {
1030
+ throw new Error("getLegacyAgentAssetDirectoryName requires a non-empty agentId");
1031
+ }
1032
+ return agentId;
1033
+ }
1034
+ function getCanonicalAgentInstructionsBundleDirName(agentName, agentId) {
1035
+ return `${getCanonicalAgentAssetDirectoryName(agentName, agentId)}-instructions`;
1036
+ }
1037
+ function getLegacyAgentInstructionsBundleDirName(agentId) {
1038
+ return `${getLegacyAgentAssetDirectoryName(agentId)}-instructions`;
1039
+ }
1040
+ function getDefaultHeartbeatProcedurePath(agentId, agentName) {
1013
1041
  if (!agentId || typeof agentId !== "string") {
1014
1042
  throw new Error("getDefaultHeartbeatProcedurePath requires a non-empty agentId");
1015
1043
  }
1016
- return `.fusion/agents/${agentId}/HEARTBEAT.md`;
1044
+ const directory = agentName ? getCanonicalAgentAssetDirectoryName(agentName, agentId) : getLegacyAgentAssetDirectoryName(agentId);
1045
+ return `.fusion/agents/${directory}/HEARTBEAT.md`;
1017
1046
  }
1018
1047
  function agentToConfigSnapshot(agent) {
1019
1048
  return {
@@ -2707,7 +2736,7 @@ var init_db = __esm({
2707
2736
  "use strict";
2708
2737
  init_sqlite_adapter();
2709
2738
  init_types();
2710
- SCHEMA_VERSION = 57;
2739
+ SCHEMA_VERSION = 58;
2711
2740
  SCHEMA_SQL = `
2712
2741
  -- Tasks table with JSON columns for nested data
2713
2742
  CREATE TABLE IF NOT EXISTS tasks (
@@ -4408,6 +4437,27 @@ CREATE INDEX IF NOT EXISTS idxTodoItemsSortOrder ON todo_items(listId, sortOrder
4408
4437
  }
4409
4438
  });
4410
4439
  }
4440
+ if (version < 58) {
4441
+ this.applyMigration(58, () => {
4442
+ const newCommand = "npx runfusion.ai backup --create";
4443
+ if (this.hasTable("automations") && this.hasColumn("automations", "command")) {
4444
+ this.db.prepare(
4445
+ `UPDATE automations
4446
+ SET command = ?, updatedAt = ?
4447
+ WHERE name = 'Database Backup'
4448
+ AND (command LIKE 'fn backup%' OR command LIKE 'kb backup%' OR command LIKE 'fusion backup%')`
4449
+ ).run(newCommand, (/* @__PURE__ */ new Date()).toISOString());
4450
+ }
4451
+ if (this.hasTable("routines") && this.hasColumn("routines", "command")) {
4452
+ this.db.prepare(
4453
+ `UPDATE routines
4454
+ SET command = ?, updatedAt = ?
4455
+ WHERE name = 'Database Backup'
4456
+ AND (command LIKE 'fn backup%' OR command LIKE 'kb backup%' OR command LIKE 'fusion backup%')`
4457
+ ).run(newCommand, (/* @__PURE__ */ new Date()).toISOString());
4458
+ }
4459
+ });
4460
+ }
4411
4461
  }
4412
4462
  /**
4413
4463
  * Run a single migration step inside a transaction and bump the version.
@@ -4671,7 +4721,7 @@ var init_agent_store = __esm({
4671
4721
  if (agent.heartbeatProcedurePath !== DEFAULT_HEARTBEAT_PROCEDURE_PATH) {
4672
4722
  continue;
4673
4723
  }
4674
- const newRelPath = getDefaultHeartbeatProcedurePath(agent.id);
4724
+ const newRelPath = await this.resolveCompatibleHeartbeatProcedurePath(agent);
4675
4725
  const newAbsPath = join3(this.rootDir, "..", newRelPath);
4676
4726
  if (legacyContent !== null) {
4677
4727
  try {
@@ -4832,7 +4882,7 @@ var init_agent_store = __esm({
4832
4882
  const metadata = input.metadata ?? {};
4833
4883
  const runtimeConfig = resolveCreationRuntimeConfig(input.runtimeConfig, metadata);
4834
4884
  const ephemeral = isEphemeralAgent({ metadata, name: input.name, role: input.role, reportsTo: input.reportsTo });
4835
- const resolvedHeartbeatProcedurePath = input.heartbeatProcedurePath ?? (ephemeral ? void 0 : getDefaultHeartbeatProcedurePath(agentId));
4885
+ const resolvedHeartbeatProcedurePath = input.heartbeatProcedurePath ?? (ephemeral ? void 0 : getDefaultHeartbeatProcedurePath(agentId, input.name));
4836
4886
  const agent = {
4837
4887
  id: agentId,
4838
4888
  name: input.name.trim(),
@@ -5069,14 +5119,16 @@ var init_agent_store = __esm({
5069
5119
  * Does not create the directory.
5070
5120
  */
5071
5121
  getInstructionsDir(agentId) {
5072
- return this.getBundleDir(agentId);
5122
+ const agent = this.readAgent(agentId);
5123
+ const agentName = agent?.name ?? "";
5124
+ return join3(this.agentsDir, getCanonicalAgentInstructionsBundleDirName(agentName, agentId));
5073
5125
  }
5074
5126
  /**
5075
5127
  * List markdown files in an agent's managed instructions bundle.
5076
5128
  * Returns [] when the bundle directory does not exist.
5077
5129
  */
5078
5130
  async listBundleFiles(agentId) {
5079
- const bundleDir = this.getBundleDir(agentId);
5131
+ const bundleDir = await this.resolveCompatibleBundleDir(agentId, false);
5080
5132
  try {
5081
5133
  const entries = await readdir(bundleDir, { withFileTypes: true });
5082
5134
  return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
@@ -5092,7 +5144,8 @@ var init_agent_store = __esm({
5092
5144
  */
5093
5145
  async readBundleFile(agentId, filePath) {
5094
5146
  this.validateBundleFilePath(filePath);
5095
- const resolvedPath = join3(this.getBundleDir(agentId), filePath);
5147
+ const bundleDir = await this.resolveCompatibleBundleDir(agentId, false);
5148
+ const resolvedPath = join3(bundleDir, filePath);
5096
5149
  return readFile(resolvedPath, "utf-8");
5097
5150
  }
5098
5151
  /**
@@ -5101,7 +5154,7 @@ var init_agent_store = __esm({
5101
5154
  async writeBundleFile(agentId, filePath, content) {
5102
5155
  return this.withLock(agentId, async () => {
5103
5156
  this.validateBundleFilePath(filePath);
5104
- const bundleDir = this.getBundleDir(agentId);
5157
+ const bundleDir = await this.resolveCompatibleBundleDir(agentId, true);
5105
5158
  await mkdir(bundleDir, { recursive: true });
5106
5159
  const existingFiles = await this.listBundleFiles(agentId);
5107
5160
  const isOverwrite = existingFiles.includes(filePath);
@@ -5120,7 +5173,8 @@ var init_agent_store = __esm({
5120
5173
  async deleteBundleFile(agentId, filePath) {
5121
5174
  return this.withLock(agentId, async () => {
5122
5175
  this.validateBundleFilePath(filePath);
5123
- await unlink(join3(this.getBundleDir(agentId), filePath));
5176
+ const bundleDir = await this.resolveCompatibleBundleDir(agentId, false);
5177
+ await unlink(join3(bundleDir, filePath));
5124
5178
  });
5125
5179
  }
5126
5180
  /**
@@ -5142,7 +5196,7 @@ var init_agent_store = __esm({
5142
5196
  };
5143
5197
  const updated = await this.updateAgent(agentId, { bundleConfig: normalizedConfig });
5144
5198
  if (normalizedConfig.mode === "managed") {
5145
- await mkdir(this.getBundleDir(agentId), { recursive: true });
5199
+ await mkdir(await this.resolveCompatibleBundleDir(agentId, true), { recursive: true });
5146
5200
  }
5147
5201
  return updated;
5148
5202
  }
@@ -5165,7 +5219,7 @@ var init_agent_store = __esm({
5165
5219
  bundleConfig: { mode: "managed", entryFile, files: [] }
5166
5220
  });
5167
5221
  }
5168
- await mkdir(this.getBundleDir(agentId), { recursive: true });
5222
+ await mkdir(await this.resolveCompatibleBundleDir(agentId, true), { recursive: true });
5169
5223
  const files = [];
5170
5224
  if (hasInstructionsText) {
5171
5225
  await this.writeBundleFile(agentId, entryFile, agent.instructionsText ?? "");
@@ -6126,8 +6180,87 @@ var init_agent_store = __esm({
6126
6180
  }
6127
6181
  return null;
6128
6182
  }
6129
- getBundleDir(agentId) {
6130
- return join3(this.agentsDir, `${agentId}-instructions`);
6183
+ getCanonicalBundleDir(agent) {
6184
+ return join3(this.agentsDir, getCanonicalAgentInstructionsBundleDirName(agent.name, agent.id));
6185
+ }
6186
+ getLegacyBundleDir(agentId) {
6187
+ return join3(this.agentsDir, getLegacyAgentInstructionsBundleDirName(agentId));
6188
+ }
6189
+ async resolveCompatibleBundleDir(agentId, createIfMissing) {
6190
+ const agent = this.readAgent(agentId);
6191
+ if (!agent) {
6192
+ throw new Error(`Agent ${agentId} not found`);
6193
+ }
6194
+ const canonicalDir = this.getCanonicalBundleDir(agent);
6195
+ if (await this.pathExists(canonicalDir)) {
6196
+ return canonicalDir;
6197
+ }
6198
+ const compatibleDir = await this.findExistingDisplayNameBundleDir(agent);
6199
+ if (compatibleDir) {
6200
+ return compatibleDir;
6201
+ }
6202
+ const legacyDir = this.getLegacyBundleDir(agent.id);
6203
+ if (await this.pathExists(legacyDir)) {
6204
+ return legacyDir;
6205
+ }
6206
+ return createIfMissing ? canonicalDir : canonicalDir;
6207
+ }
6208
+ async findExistingDisplayNameBundleDir(agent) {
6209
+ const safeId = getSafeAgentAssetIdSegment(agent.id);
6210
+ try {
6211
+ const entries = await readdir(this.agentsDir, { withFileTypes: true });
6212
+ const candidates = entries.filter((entry) => entry.isDirectory() && entry.name.endsWith("-instructions")).map((entry) => entry.name).filter((name) => {
6213
+ const base = name.slice(0, -"-instructions".length);
6214
+ return base.endsWith(`-${safeId}`);
6215
+ }).sort((a, b) => a.localeCompare(b));
6216
+ if (candidates.length === 0) {
6217
+ return null;
6218
+ }
6219
+ const canonicalName = getCanonicalAgentInstructionsBundleDirName(agent.name, agent.id);
6220
+ const selected = candidates.find((candidate) => candidate === canonicalName) ?? candidates[0];
6221
+ return join3(this.agentsDir, selected);
6222
+ } catch (err) {
6223
+ if (err.code === "ENOENT") {
6224
+ return null;
6225
+ }
6226
+ throw err;
6227
+ }
6228
+ }
6229
+ async resolveCompatibleHeartbeatProcedurePath(agent) {
6230
+ const canonicalPath = getDefaultHeartbeatProcedurePath(agent.id, agent.name);
6231
+ const canonicalAbs = join3(this.rootDir, "..", canonicalPath);
6232
+ if (await this.pathExists(canonicalAbs)) {
6233
+ return canonicalPath;
6234
+ }
6235
+ const safeId = getSafeAgentAssetIdSegment(agent.id);
6236
+ try {
6237
+ const entries = await readdir(this.agentsDir, { withFileTypes: true });
6238
+ const compatibleDir = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).find((name) => name.endsWith(`-${safeId}`));
6239
+ if (compatibleDir) {
6240
+ const candidatePath = `.fusion/agents/${compatibleDir}/HEARTBEAT.md`;
6241
+ if (await this.pathExists(join3(this.rootDir, "..", candidatePath))) {
6242
+ return candidatePath;
6243
+ }
6244
+ }
6245
+ } catch (err) {
6246
+ if (err.code !== "ENOENT") {
6247
+ throw err;
6248
+ }
6249
+ }
6250
+ const legacyPath = `.fusion/agents/${getLegacyAgentAssetDirectoryName(agent.id)}/HEARTBEAT.md`;
6251
+ const legacyAbs = join3(this.rootDir, "..", legacyPath);
6252
+ if (await this.pathExists(legacyAbs)) {
6253
+ return legacyPath;
6254
+ }
6255
+ return canonicalPath;
6256
+ }
6257
+ async pathExists(path5) {
6258
+ try {
6259
+ await access(path5, fsConstants.F_OK);
6260
+ return true;
6261
+ } catch {
6262
+ return false;
6263
+ }
6131
6264
  }
6132
6265
  validateBundleFilePath(filePath) {
6133
6266
  if (typeof filePath !== "string") {
@@ -7013,9 +7146,9 @@ var init_global_settings = __esm({
7013
7146
  * Serialize operations via promise chain to prevent lost-update races.
7014
7147
  */
7015
7148
  withLock(fn) {
7016
- let resolve40;
7149
+ let resolve42;
7017
7150
  const next = new Promise((r) => {
7018
- resolve40 = r;
7151
+ resolve42 = r;
7019
7152
  });
7020
7153
  const prev = this.lock;
7021
7154
  this.lock = next;
@@ -7023,7 +7156,7 @@ var init_global_settings = __esm({
7023
7156
  try {
7024
7157
  return await fn();
7025
7158
  } finally {
7026
- resolve40();
7159
+ resolve42();
7027
7160
  }
7028
7161
  });
7029
7162
  }
@@ -28483,8 +28616,8 @@ var require_CronFileParser = __commonJS({
28483
28616
  * @throws If file cannot be read
28484
28617
  */
28485
28618
  static parseFileSync(filePath) {
28486
- const { readFileSync: readFileSync24 } = __require("fs");
28487
- const data = readFileSync24(filePath, "utf8");
28619
+ const { readFileSync: readFileSync25 } = __require("fs");
28620
+ const data = readFileSync25(filePath, "utf8");
28488
28621
  return _CronFileParser.#parseContent(data);
28489
28622
  }
28490
28623
  /**
@@ -28701,9 +28834,9 @@ var init_automation_store = __esm({
28701
28834
  */
28702
28835
  withScheduleLock(id, fn) {
28703
28836
  const prev = this.scheduleLocks.get(id) ?? Promise.resolve();
28704
- let resolve40;
28837
+ let resolve42;
28705
28838
  const next = new Promise((r) => {
28706
- resolve40 = r;
28839
+ resolve42 = r;
28707
28840
  });
28708
28841
  this.scheduleLocks.set(id, next);
28709
28842
  return prev.then(async () => {
@@ -28713,7 +28846,7 @@ var init_automation_store = __esm({
28713
28846
  if (this.scheduleLocks.get(id) === next) {
28714
28847
  this.scheduleLocks.delete(id);
28715
28848
  }
28716
- resolve40();
28849
+ resolve42();
28717
28850
  }
28718
28851
  });
28719
28852
  }
@@ -30502,7 +30635,7 @@ var init_project_memory = __esm({
30502
30635
  // ../core/src/run-command.ts
30503
30636
  import { spawn } from "node:child_process";
30504
30637
  function runCommandAsync(command, options = {}) {
30505
- return new Promise((resolve40) => {
30638
+ return new Promise((resolve42) => {
30506
30639
  const maxBuffer = options.maxBuffer ?? DEFAULT_MAX_BUFFER;
30507
30640
  let stdout = "";
30508
30641
  let stderr = "";
@@ -30561,7 +30694,7 @@ function runCommandAsync(command, options = {}) {
30561
30694
  clearTimeout(forceKillTimer);
30562
30695
  forceKillTimer = null;
30563
30696
  }
30564
- resolve40({
30697
+ resolve42({
30565
30698
  stdout,
30566
30699
  stderr,
30567
30700
  exitCode: null,
@@ -30579,7 +30712,7 @@ function runCommandAsync(command, options = {}) {
30579
30712
  }
30580
30713
  signalProcessGroup("SIGTERM");
30581
30714
  scheduleForceKill(NORMAL_CLEANUP_FORCE_KILL_DELAY_MS);
30582
- resolve40({
30715
+ resolve42({
30583
30716
  stdout,
30584
30717
  stderr,
30585
30718
  exitCode: code,
@@ -31794,9 +31927,9 @@ ${outcome}`;
31794
31927
  * lost-update races on the nextId counter.
31795
31928
  */
31796
31929
  withConfigLock(fn) {
31797
- let resolve40;
31930
+ let resolve42;
31798
31931
  const next = new Promise((r) => {
31799
- resolve40 = r;
31932
+ resolve42 = r;
31800
31933
  });
31801
31934
  const prev = this.configLock;
31802
31935
  this.configLock = next;
@@ -31804,7 +31937,7 @@ ${outcome}`;
31804
31937
  try {
31805
31938
  return await fn();
31806
31939
  } finally {
31807
- resolve40();
31940
+ resolve42();
31808
31941
  }
31809
31942
  });
31810
31943
  }
@@ -31814,9 +31947,9 @@ ${outcome}`;
31814
31947
  */
31815
31948
  withTaskLock(id, fn) {
31816
31949
  const prev = this.taskLocks.get(id) ?? Promise.resolve();
31817
- let resolve40;
31950
+ let resolve42;
31818
31951
  const next = new Promise((r) => {
31819
- resolve40 = r;
31952
+ resolve42 = r;
31820
31953
  });
31821
31954
  this.taskLocks.set(id, next);
31822
31955
  return prev.then(async () => {
@@ -31826,7 +31959,7 @@ ${outcome}`;
31826
31959
  if (this.taskLocks.get(id) === next) {
31827
31960
  this.taskLocks.delete(id);
31828
31961
  }
31829
- resolve40();
31962
+ resolve42();
31830
31963
  }
31831
31964
  });
31832
31965
  }
@@ -34094,7 +34227,7 @@ ${task.description}
34094
34227
  }
34095
34228
  }
34096
34229
  }
34097
- await new Promise((resolve40) => setImmediate(resolve40));
34230
+ await new Promise((resolve42) => setImmediate(resolve42));
34098
34231
  const selectClause = this.getTaskSelectClause(true);
34099
34232
  const changedRows = this.lastPollTime ? this.db.prepare(`SELECT ${selectClause} FROM tasks WHERE updatedAt > ? OR columnMovedAt > ?`).all(this.lastPollTime, this.lastPollTime) : this.db.prepare(`SELECT ${selectClause} FROM tasks`).all();
34100
34233
  this.lastPollTime = (/* @__PURE__ */ new Date()).toISOString();
@@ -34114,7 +34247,7 @@ ${task.description}
34114
34247
  this.emit("task:updated", task);
34115
34248
  }
34116
34249
  if (i > 0 && i % 50 === 0) {
34117
- await new Promise((resolve40) => setImmediate(resolve40));
34250
+ await new Promise((resolve42) => setImmediate(resolve42));
34118
34251
  }
34119
34252
  }
34120
34253
  const elapsed = Date.now() - startTime;
@@ -35859,6 +35992,20 @@ function reconcileClaudeCliPaths(paths, vendoredPath) {
35859
35992
  }
35860
35993
  return filtered;
35861
35994
  }
35995
+ function isExternalDroidCliPath(p, vendoredPath) {
35996
+ if (vendoredPath && p === vendoredPath) return false;
35997
+ return /(^|[/\\])droid-cli([/\\]|$)/i.test(p);
35998
+ }
35999
+ function reconcileDroidCliPaths(paths, vendoredPath) {
36000
+ if (!vendoredPath) {
36001
+ return [...paths];
36002
+ }
36003
+ const filtered = paths.filter((p) => !isExternalDroidCliPath(p, vendoredPath));
36004
+ if (!filtered.includes(vendoredPath)) {
36005
+ return [vendoredPath, ...filtered];
36006
+ }
36007
+ return filtered;
36008
+ }
35862
36009
  function getDisplayPathWithinRoot(root, targetPath) {
35863
36010
  const usesWindowsPaths = /^[A-Za-z]:[\\/]/.test(root) || /^[A-Za-z]:[\\/]/.test(targetPath) || root.includes("\\") || targetPath.includes("\\");
35864
36011
  const pathApi = usesWindowsPaths ? win32 : { relative: relative2, isAbsolute: isAbsolute5, sep: sep4 };
@@ -35970,7 +36117,7 @@ function runGh(args, cwd) {
35970
36117
  }
35971
36118
  function runGhAsync(args, cwdOrOptions) {
35972
36119
  const { cwd, signal: externalSignal, timeoutMs = DEFAULT_GH_TIMEOUT_MS } = normalizeRunGhOptions(cwdOrOptions);
35973
- return new Promise((resolve40, reject2) => {
36120
+ return new Promise((resolve42, reject2) => {
35974
36121
  if (externalSignal?.aborted) {
35975
36122
  reject2(makeGhError(`gh command aborted: ${describeAbortReason(externalSignal.reason)}`, "ABORT_ERR"));
35976
36123
  return;
@@ -36021,7 +36168,7 @@ function runGhAsync(args, cwdOrOptions) {
36021
36168
  ghError.stderr = stderr ?? "";
36022
36169
  reject2(ghError);
36023
36170
  } else {
36024
- resolve40(stdout ?? "");
36171
+ resolve42(stdout ?? "");
36025
36172
  }
36026
36173
  }
36027
36174
  );
@@ -36116,6 +36263,85 @@ var init_gh_cli = __esm({
36116
36263
  }
36117
36264
  });
36118
36265
 
36266
+ // ../core/src/fn-binary.ts
36267
+ import { spawn as spawn2 } from "node:child_process";
36268
+ import { platform as platform2 } from "node:os";
36269
+ function runProbe(command, args, timeoutMs) {
36270
+ return new Promise((resolve42) => {
36271
+ let stdout = "";
36272
+ let stderr = "";
36273
+ const child = spawn2(command, args, { stdio: ["ignore", "pipe", "pipe"], shell: false });
36274
+ const timer = setTimeout(() => {
36275
+ try {
36276
+ child.kill("SIGKILL");
36277
+ } catch {
36278
+ }
36279
+ }, timeoutMs);
36280
+ child.stdout?.on("data", (chunk) => {
36281
+ stdout += chunk.toString("utf8");
36282
+ });
36283
+ child.stderr?.on("data", (chunk) => {
36284
+ stderr += chunk.toString("utf8");
36285
+ });
36286
+ child.on("error", (err) => {
36287
+ clearTimeout(timer);
36288
+ resolve42({ exitCode: null, stdout, stderr: stderr || err.message });
36289
+ });
36290
+ child.on("close", (exitCode) => {
36291
+ clearTimeout(timer);
36292
+ resolve42({ exitCode, stdout, stderr });
36293
+ });
36294
+ });
36295
+ }
36296
+ async function whichBinary(name) {
36297
+ const isWindows = platform2() === "win32";
36298
+ const lookup = isWindows ? "where" : "which";
36299
+ const result = await runProbe(lookup, [name], 5e3);
36300
+ if (result.exitCode !== 0) return void 0;
36301
+ const firstLine = result.stdout.split(/\r?\n/).map((s) => s.trim()).find(Boolean);
36302
+ return firstLine || void 0;
36303
+ }
36304
+ async function probeVersion(binary) {
36305
+ const result = await runProbe(binary, ["--version"], 1e4);
36306
+ if (result.exitCode !== 0) return void 0;
36307
+ const text = (result.stdout || result.stderr).trim();
36308
+ if (!text) return void 0;
36309
+ const match = text.match(/\d+\.\d+\.\d+(?:-[\w.]+)?/);
36310
+ return match ? match[0] : text.split(/\s+/)[0];
36311
+ }
36312
+ async function detectFnBinary() {
36313
+ for (const candidate of CANDIDATES) {
36314
+ try {
36315
+ const resolvedPath = await whichBinary(candidate);
36316
+ if (!resolvedPath) continue;
36317
+ const version = await probeVersion(candidate);
36318
+ return {
36319
+ installed: true,
36320
+ binary: candidate,
36321
+ path: resolvedPath,
36322
+ version,
36323
+ invocation: candidate
36324
+ };
36325
+ } catch {
36326
+ }
36327
+ }
36328
+ return {
36329
+ installed: false,
36330
+ invocation: FN_NPX_INVOCATION
36331
+ };
36332
+ }
36333
+ var FN_NPM_PACKAGE, FN_INSTALL_CURL, FN_INSTALL_NPM, FN_NPX_INVOCATION, CANDIDATES;
36334
+ var init_fn_binary = __esm({
36335
+ "../core/src/fn-binary.ts"() {
36336
+ "use strict";
36337
+ FN_NPM_PACKAGE = "runfusion.ai";
36338
+ FN_INSTALL_CURL = "curl -fsSL https://runfusion.ai/install.sh | sh";
36339
+ FN_INSTALL_NPM = `npm install -g ${FN_NPM_PACKAGE}`;
36340
+ FN_NPX_INVOCATION = `npx -y ${FN_NPM_PACKAGE}`;
36341
+ CANDIDATES = ["fn", "fusion"];
36342
+ }
36343
+ });
36344
+
36119
36345
  // ../core/src/settings-validation.ts
36120
36346
  function validateUnavailableNodePolicy(value) {
36121
36347
  if (value === void 0) {
@@ -36309,9 +36535,9 @@ var init_routine_store = __esm({
36309
36535
  */
36310
36536
  withRoutineLock(id, fn) {
36311
36537
  const prev = this.routineLocks.get(id) ?? Promise.resolve();
36312
- let resolve40;
36538
+ let resolve42;
36313
36539
  const next = new Promise((r) => {
36314
- resolve40 = r;
36540
+ resolve42 = r;
36315
36541
  });
36316
36542
  this.routineLocks.set(id, next);
36317
36543
  return prev.then(async () => {
@@ -36321,7 +36547,7 @@ var init_routine_store = __esm({
36321
36547
  if (this.routineLocks.get(id) === next) {
36322
36548
  this.routineLocks.delete(id);
36323
36549
  }
36324
- resolve40();
36550
+ resolve42();
36325
36551
  }
36326
36552
  });
36327
36553
  }
@@ -36920,13 +37146,13 @@ var init_plugin_loader = __esm({
36920
37146
  * Execute a promise with a timeout.
36921
37147
  */
36922
37148
  withTimeout(promise, ms, timeoutMessage) {
36923
- return new Promise((resolve40, reject2) => {
37149
+ return new Promise((resolve42, reject2) => {
36924
37150
  const timer = setTimeout(() => {
36925
37151
  reject2(new Error(timeoutMessage));
36926
37152
  }, ms);
36927
37153
  promise.then((result) => {
36928
37154
  clearTimeout(timer);
36929
- resolve40(result);
37155
+ resolve42(result);
36930
37156
  }).catch((err) => {
36931
37157
  clearTimeout(timer);
36932
37158
  reject2(err);
@@ -40491,7 +40717,7 @@ var require_get_stream = __commonJS({
40491
40717
  };
40492
40718
  const { maxBuffer } = options;
40493
40719
  let stream;
40494
- await new Promise((resolve40, reject2) => {
40720
+ await new Promise((resolve42, reject2) => {
40495
40721
  const rejectPromise = (error) => {
40496
40722
  if (error && stream.getBufferedLength() <= BufferConstants.MAX_LENGTH) {
40497
40723
  error.bufferedData = stream.getBufferedValue();
@@ -40503,7 +40729,7 @@ var require_get_stream = __commonJS({
40503
40729
  rejectPromise(error);
40504
40730
  return;
40505
40731
  }
40506
- resolve40();
40732
+ resolve42();
40507
40733
  });
40508
40734
  stream.on("data", () => {
40509
40735
  if (stream.getBufferedLength() > maxBuffer) {
@@ -41797,7 +42023,7 @@ var require_extract_zip = __commonJS({
41797
42023
  debug("opening", this.zipPath, "with opts", this.opts);
41798
42024
  this.zipfile = await openZip(this.zipPath, { lazyEntries: true });
41799
42025
  this.canceled = false;
41800
- return new Promise((resolve40, reject2) => {
42026
+ return new Promise((resolve42, reject2) => {
41801
42027
  this.zipfile.on("error", (err) => {
41802
42028
  this.canceled = true;
41803
42029
  reject2(err);
@@ -41806,7 +42032,7 @@ var require_extract_zip = __commonJS({
41806
42032
  this.zipfile.on("close", () => {
41807
42033
  if (!this.canceled) {
41808
42034
  debug("zip extraction complete");
41809
- resolve40();
42035
+ resolve42();
41810
42036
  }
41811
42037
  });
41812
42038
  this.zipfile.on("entry", async (entry) => {
@@ -50403,6 +50629,10 @@ __export(src_exports, {
50403
50629
  EXECUTION_MODES: () => EXECUTION_MODES,
50404
50630
  FEATURE_LOOP_STATES: () => FEATURE_LOOP_STATES,
50405
50631
  FEATURE_STATUSES: () => FEATURE_STATUSES,
50632
+ FN_INSTALL_CURL: () => FN_INSTALL_CURL,
50633
+ FN_INSTALL_NPM: () => FN_INSTALL_NPM,
50634
+ FN_NPM_PACKAGE: () => FN_NPM_PACKAGE,
50635
+ FN_NPX_INVOCATION: () => FN_NPX_INVOCATION,
50406
50636
  FileMemoryBackend: () => FileMemoryBackend,
50407
50637
  FirstRunDetector: () => FirstRunDetector,
50408
50638
  GLOBAL_SETTINGS_KEYS: () => GLOBAL_SETTINGS_KEYS,
@@ -50514,6 +50744,7 @@ __export(src_exports, {
50514
50744
  createInsightExtractionAutomation: () => createInsightExtractionAutomation,
50515
50745
  createMemoryDreamsAutomation: () => createMemoryDreamsAutomation,
50516
50746
  dailyMemoryPath: () => dailyMemoryPath,
50747
+ detectFnBinary: () => detectFnBinary,
50517
50748
  detectLegacyData: () => detectLegacyData,
50518
50749
  diffConfigSnapshots: () => diffConfigSnapshots,
50519
50750
  discoverPiExtensions: () => discoverPiExtensions,
@@ -50635,6 +50866,7 @@ __export(src_exports, {
50635
50866
  readProjectMemoryWithBackend: () => readProjectMemoryWithBackend,
50636
50867
  readWorkingMemory: () => readWorkingMemory,
50637
50868
  reconcileClaudeCliPaths: () => reconcileClaudeCliPaths,
50869
+ reconcileDroidCliPaths: () => reconcileDroidCliPaths,
50638
50870
  refreshQmdProjectMemoryIndex: () => refreshQmdProjectMemoryIndex,
50639
50871
  registerMemoryBackend: () => registerMemoryBackend,
50640
50872
  renderMemoryAuditMarkdown: () => renderMemoryAuditMarkdown,
@@ -50724,6 +50956,7 @@ var init_src = __esm({
50724
50956
  init_automation();
50725
50957
  init_automation_store();
50726
50958
  init_run_command();
50959
+ init_fn_binary();
50727
50960
  init_node_override_guard();
50728
50961
  init_settings_validation();
50729
50962
  init_routine();
@@ -51885,12 +52118,12 @@ var init_concurrency = __esm({
51885
52118
  this._active++;
51886
52119
  return Promise.resolve();
51887
52120
  }
51888
- return new Promise((resolve40) => {
52121
+ return new Promise((resolve42) => {
51889
52122
  this._waiters.push({
51890
52123
  priority,
51891
52124
  resolve: () => {
51892
52125
  this._active++;
51893
- resolve40();
52126
+ resolve42();
51894
52127
  }
51895
52128
  });
51896
52129
  });
@@ -53454,8 +53687,23 @@ function getPackageManagerAgentDir() {
53454
53687
  }
53455
53688
  function resolveVendoredClaudeCliEntry() {
53456
53689
  try {
53457
- const require_2 = createRequire2(import.meta.url);
53458
- const pkgJsonPath = require_2.resolve("@fusion/pi-claude-cli/package.json");
53690
+ const require_3 = createRequire2(import.meta.url);
53691
+ const pkgJsonPath = require_3.resolve("@fusion/pi-claude-cli/package.json");
53692
+ const pkgJson = JSON.parse(readFileSync9(pkgJsonPath, "utf-8"));
53693
+ const extensions = pkgJson.pi?.extensions;
53694
+ if (!Array.isArray(extensions) || extensions.length === 0) return null;
53695
+ const entry = extensions[0];
53696
+ if (typeof entry !== "string" || entry.length === 0) return null;
53697
+ const path5 = resolve11(dirname8(pkgJsonPath), entry);
53698
+ return existsSync20(path5) ? path5 : null;
53699
+ } catch {
53700
+ return null;
53701
+ }
53702
+ }
53703
+ function resolveVendoredDroidCliEntry() {
53704
+ try {
53705
+ const require_3 = createRequire2(import.meta.url);
53706
+ const pkgJsonPath = require_3.resolve("@fusion/droid-cli/package.json");
53459
53707
  const pkgJson = JSON.parse(readFileSync9(pkgJsonPath, "utf-8"));
53460
53708
  const extensions = pkgJson.pi?.extensions;
53461
53709
  if (!Array.isArray(extensions) || extensions.length === 0) return null;
@@ -53482,8 +53730,13 @@ async function registerExtensionProviders(cwd, modelRegistry) {
53482
53730
  [...getEnabledPiExtensionPaths(cwd), ...packageExtensionPaths],
53483
53731
  vendoredClaudeCli
53484
53732
  );
53485
- const extensionsResult = await discoverAndLoadExtensions(
53733
+ const vendoredDroidCli = resolveVendoredDroidCliEntry();
53734
+ const doubleReconciledPaths = reconcileDroidCliPaths(
53486
53735
  reconciledPaths,
53736
+ vendoredDroidCli
53737
+ );
53738
+ const extensionsResult = await discoverAndLoadExtensions(
53739
+ doubleReconciledPaths,
53487
53740
  cwd,
53488
53741
  join25(resolvePiExtensionProjectRoot(cwd), ".fusion", "disabled-auto-extension-discovery")
53489
53742
  );
@@ -54422,8 +54675,8 @@ var init_page_fetch_provider = __esm({
54422
54675
 
54423
54676
  // ../engine/src/research/providers/web-search-provider.ts
54424
54677
  async function sleep(ms, signal) {
54425
- await new Promise((resolve40, reject2) => {
54426
- const timer = setTimeout(resolve40, ms);
54678
+ await new Promise((resolve42, reject2) => {
54679
+ const timer = setTimeout(resolve42, ms);
54427
54680
  const onAbort = () => {
54428
54681
  clearTimeout(timer);
54429
54682
  reject2(new ResearchProviderError({ providerType: "web-search", code: "abort", message: "Search aborted" }));
@@ -55140,14 +55393,25 @@ async function getAgentMemoryWindow(rootDir, agentMemory, path5, startLine = 1,
55140
55393
  backend: "agent-memory"
55141
55394
  };
55142
55395
  }
55143
- function createTaskCreateTool(store, provenance) {
55396
+ async function createAgentTask(store, input, options) {
55397
+ const settings = typeof store.getSettings === "function" ? await store.getSettings() : {};
55398
+ const rootDir = options?.rootDir;
55399
+ return store.createTask(input, {
55400
+ settings: { autoSummarizeTitles: settings.autoSummarizeTitles === true },
55401
+ onSummarize: rootDir ? async (description) => {
55402
+ const resolved = resolveTitleSummarizerSettingsModel(settings);
55403
+ return summarizeTitle(description, rootDir, resolved.provider, resolved.modelId);
55404
+ } : void 0
55405
+ });
55406
+ }
55407
+ function createTaskCreateTool(store, provenance, options) {
55144
55408
  return {
55145
55409
  name: "fn_task_create",
55146
55410
  label: "Create Task",
55147
55411
  description: "Create a new task for out-of-scope work discovered during execution. The task goes into triage where it will be specified by the AI. Optionally set dependencies (e.g., the new task depends on the current one, or the current task should wait for the new one).",
55148
55412
  parameters: taskCreateParams,
55149
55413
  execute: async (_id, params) => {
55150
- const task = await store.createTask({
55414
+ const task = await createAgentTask(store, {
55151
55415
  description: params.description,
55152
55416
  dependencies: params.dependencies,
55153
55417
  column: "triage",
@@ -55156,7 +55420,7 @@ function createTaskCreateTool(store, provenance) {
55156
55420
  sourceAgentId: provenance.sourceAgentId,
55157
55421
  sourceRunId: provenance.sourceRunId
55158
55422
  } : void 0
55159
- });
55423
+ }, options);
55160
55424
  const deps = task.dependencies.length ? ` (depends on: ${task.dependencies.join(", ")})` : "";
55161
55425
  return {
55162
55426
  content: [{
@@ -55509,7 +55773,7 @@ ${lines.join("\n\n")}` }],
55509
55773
  }
55510
55774
  };
55511
55775
  }
55512
- function createDelegateTaskTool(agentStore, taskStore) {
55776
+ function createDelegateTaskTool(agentStore, taskStore, options) {
55513
55777
  return {
55514
55778
  name: "fn_delegate_task",
55515
55779
  label: "Delegate Task",
@@ -55529,13 +55793,13 @@ function createDelegateTaskTool(agentStore, taskStore) {
55529
55793
  details: {}
55530
55794
  };
55531
55795
  }
55532
- const task = await taskStore.createTask({
55796
+ const task = await createAgentTask(taskStore, {
55533
55797
  description: params.description,
55534
55798
  dependencies: params.dependencies,
55535
55799
  column: "todo",
55536
55800
  assignedAgentId: params.agent_id,
55537
55801
  source: { sourceType: "api" }
55538
- });
55802
+ }, options);
55539
55803
  const deps = task.dependencies.length ? ` (depends on: ${task.dependencies.join(", ")})` : "";
55540
55804
  return {
55541
55805
  content: [{
@@ -55710,9 +55974,9 @@ function createResearchTools(options) {
55710
55974
  const maxWaitMs = Math.max(1e3, Math.min(params.max_wait_ms ?? 9e4, resolved.limits.maxDurationMs));
55711
55975
  const completed = await Promise.race([
55712
55976
  runPromise,
55713
- new Promise((resolve40) => setTimeout(() => {
55977
+ new Promise((resolve42) => setTimeout(() => {
55714
55978
  const latest = options.store.getResearchStore().getRun(runId);
55715
- resolve40(latest ?? {
55979
+ resolve42(latest ?? {
55716
55980
  id: runId,
55717
55981
  query: params.query,
55718
55982
  status: "running",
@@ -57286,20 +57550,20 @@ async function withRateLimitRetry(fn, options = {}) {
57286
57550
  throw lastError ?? new Error("withRateLimitRetry: unexpected state");
57287
57551
  }
57288
57552
  function sleep2(ms, signal) {
57289
- return new Promise((resolve40, reject2) => {
57553
+ return new Promise((resolve42, reject2) => {
57290
57554
  if (signal?.aborted) {
57291
57555
  reject2(signal.reason ?? new Error("Aborted"));
57292
57556
  return;
57293
57557
  }
57294
- const timer = setTimeout(resolve40, ms);
57558
+ const timer = setTimeout(resolve42, ms);
57295
57559
  if (signal) {
57296
57560
  const onAbort = () => {
57297
57561
  clearTimeout(timer);
57298
57562
  reject2(signal.reason ?? new Error("Aborted"));
57299
57563
  };
57300
57564
  signal.addEventListener("abort", onAbort, { once: true });
57301
- const origResolve = resolve40;
57302
- resolve40 = () => {
57565
+ const origResolve = resolve42;
57566
+ resolve42 = () => {
57303
57567
  signal.removeEventListener("abort", onAbort);
57304
57568
  origResolve();
57305
57569
  };
@@ -58362,7 +58626,7 @@ Write the PROMPT.md directly using the write tool, then call \`fn_review_spec()\
58362
58626
  // Agent delegation tools — discover and delegate work to other agents.
58363
58627
  ...this.options.agentStore ? [
58364
58628
  createListAgentsTool(this.options.agentStore),
58365
- createDelegateTaskTool(this.options.agentStore, this.store)
58629
+ createDelegateTaskTool(this.options.agentStore, this.store, { rootDir: this.rootDir })
58366
58630
  ] : [],
58367
58631
  this.createReviewSpecTool(
58368
58632
  task.id,
@@ -58901,7 +59165,7 @@ Remove or replace these ids and call fn_task_create again.`
58901
59165
  planLog.warn(`${options.parentTaskId}: failed to load parent task for fn_task_create inheritance: ${msg}`);
58902
59166
  parentTask = void 0;
58903
59167
  }
58904
- const newTask = await store.createTask({
59168
+ const newTask = await createAgentTask(store, {
58905
59169
  title: params.title,
58906
59170
  description: params.description,
58907
59171
  dependencies: validDeps,
@@ -58915,7 +59179,7 @@ Remove or replace these ids and call fn_task_create again.`
58915
59179
  sourceType: "agent_heartbeat",
58916
59180
  sourceParentTaskId: options.parentTaskId
58917
59181
  }
58918
- });
59182
+ }, { rootDir: this.rootDir });
58919
59183
  options.createdSubtasksRef.current.push(newTask.id);
58920
59184
  return {
58921
59185
  content: [
@@ -59343,13 +59607,13 @@ var init_run_audit = __esm({
59343
59607
  });
59344
59608
 
59345
59609
  // ../engine/src/merger.ts
59346
- import { execSync, exec as exec2, spawn as spawn2 } from "node:child_process";
59610
+ import { execSync, exec as exec2, spawn as spawn3 } from "node:child_process";
59347
59611
  import { promisify as promisify3 } from "node:util";
59348
59612
  import { existsSync as existsSync22 } from "node:fs";
59349
59613
  import { join as join29 } from "node:path";
59350
59614
  import { Type as Type3 } from "typebox";
59351
59615
  async function execWithProcessGroup(command, options) {
59352
- return new Promise((resolve40, reject2) => {
59616
+ return new Promise((resolve42, reject2) => {
59353
59617
  if (options.signal?.aborted) {
59354
59618
  reject2(Object.assign(
59355
59619
  new Error(`Command aborted before start: ${command}`),
@@ -59358,7 +59622,7 @@ async function execWithProcessGroup(command, options) {
59358
59622
  return;
59359
59623
  }
59360
59624
  const useProcessGroup = process.platform !== "win32";
59361
- const child = spawn2(command, {
59625
+ const child = spawn3(command, {
59362
59626
  cwd: options.cwd,
59363
59627
  shell: true,
59364
59628
  detached: useProcessGroup,
@@ -59442,7 +59706,7 @@ async function execWithProcessGroup(command, options) {
59442
59706
  return;
59443
59707
  }
59444
59708
  if (code === 0) {
59445
- resolve40({ stdout, stderr, bufferOverflow: stdoutOverflow || stderrOverflow });
59709
+ resolve42({ stdout, stderr, bufferOverflow: stdoutOverflow || stderrOverflow });
59446
59710
  return;
59447
59711
  }
59448
59712
  reject2(Object.assign(
@@ -63866,7 +64130,7 @@ function resolveExecutorModelPair(taskModelProvider, taskModelId, settings) {
63866
64130
  return { provider: void 0, modelId: void 0 };
63867
64131
  }
63868
64132
  function sleep3(ms) {
63869
- return new Promise((resolve40) => setTimeout(resolve40, ms));
64133
+ return new Promise((resolve42) => setTimeout(resolve42, ms));
63870
64134
  }
63871
64135
  var execAsync4, stepExecLog, MAX_STEP_RETRIES, RETRY_DELAYS_MS, NOOP_TASK_STORE, StepSessionExecutor;
63872
64136
  var init_step_session_executor = __esm({
@@ -64094,10 +64358,10 @@ var init_step_session_executor = __esm({
64094
64358
  ] : [];
64095
64359
  const memoryTools = createMemoryTools(this.options.rootDir, settings);
64096
64360
  const taskLogTool = this.options.store ? [createTaskLogTool(this.options.store, taskDetail.id)] : [];
64097
- const taskCreateTool = this.options.store ? [createTaskCreateTool(this.options.store)] : [];
64361
+ const taskCreateTool = this.options.store ? [createTaskCreateTool(this.options.store, void 0, { rootDir: this.options.rootDir })] : [];
64098
64362
  const delegationTools = this.options.agentStore ? [
64099
64363
  createListAgentsTool(this.options.agentStore),
64100
- createDelegateTaskTool(this.options.agentStore, this.options.store)
64364
+ createDelegateTaskTool(this.options.agentStore, this.options.store, { rootDir: this.options.rootDir })
64101
64365
  ] : [];
64102
64366
  const messagingTools = this.options.messageStore && taskDetail.assignedAgentId ? [
64103
64367
  createSendMessageTool(this.options.messageStore, taskDetail.assignedAgentId),
@@ -64508,7 +64772,7 @@ var init_task_completion = __esm({
64508
64772
  });
64509
64773
 
64510
64774
  // ../engine/src/run-verification-tool.ts
64511
- import { spawn as spawn3 } from "node:child_process";
64775
+ import { spawn as spawn4 } from "node:child_process";
64512
64776
  import { existsSync as existsSync26 } from "node:fs";
64513
64777
  import { isAbsolute as isAbsolute10, join as join34 } from "node:path";
64514
64778
  import { Type as Type4 } from "@mariozechner/pi-ai";
@@ -64540,8 +64804,8 @@ async function runVerificationCommand2(opts) {
64540
64804
  const warnings = [];
64541
64805
  const stdoutBuf = { head: "", tail: "", totalBytes: 0 };
64542
64806
  const stderrBuf = { head: "", tail: "", totalBytes: 0 };
64543
- return new Promise((resolve40) => {
64544
- const child = spawn3(command, {
64807
+ return new Promise((resolve42) => {
64808
+ const child = spawn4(command, {
64545
64809
  cwd,
64546
64810
  stdio: ["ignore", "pipe", "pipe"],
64547
64811
  env: { ...process.env },
@@ -64619,7 +64883,7 @@ async function runVerificationCommand2(opts) {
64619
64883
  `[fn_run_verification] command failed (exit=${exitCode}, signal=${signal ?? "none"}): ${command}`
64620
64884
  );
64621
64885
  }
64622
- resolve40({
64886
+ resolve42({
64623
64887
  success,
64624
64888
  exitCode,
64625
64889
  durationMs,
@@ -64639,7 +64903,7 @@ async function runVerificationCommand2(opts) {
64639
64903
  clearTimeout(hardTimer);
64640
64904
  const durationMs = Date.now() - startMs;
64641
64905
  warnings.push(`Spawn error: ${err.message}`);
64642
- resolve40({
64906
+ resolve42({
64643
64907
  success: false,
64644
64908
  exitCode: null,
64645
64909
  durationMs,
@@ -66829,7 +67093,7 @@ The tool prevents your session from being killed by the inactivity watchdog duri
66829
67093
  // Agent delegation tools — discover and delegate work to other agents.
66830
67094
  ...this.options.agentStore ? [
66831
67095
  createListAgentsTool(this.options.agentStore),
66832
- createDelegateTaskTool(this.options.agentStore, this.store)
67096
+ createDelegateTaskTool(this.options.agentStore, this.store, { rootDir: this.rootDir })
66833
67097
  ] : [],
66834
67098
  // Messaging tools — allows executor agents to send and receive messages.
66835
67099
  ...this.options.messageStore && assignedAgentId ? [
@@ -67523,7 +67787,7 @@ The tool prevents your session from being killed by the inactivity watchdog duri
67523
67787
  return createTaskLogTool(this.store, taskId);
67524
67788
  }
67525
67789
  createTaskCreateTool() {
67526
- return createTaskCreateTool(this.store, { sourceType: "api" });
67790
+ return createTaskCreateTool(this.store, { sourceType: "api" }, { rootDir: this.rootDir });
67527
67791
  }
67528
67792
  createTaskDocumentWriteTool(taskId) {
67529
67793
  return createTaskDocumentWriteTool(this.store, taskId);
@@ -68617,7 +68881,7 @@ Review the work done in this worktree and evaluate it against the criteria in yo
68617
68881
  );
68618
68882
  }
68619
68883
  const delay2 = this.WORKTREE_RETRY_DELAYS[attempt] || 1e3;
68620
- await new Promise((resolve40) => setTimeout(resolve40, delay2));
68884
+ await new Promise((resolve42) => setTimeout(resolve42, delay2));
68621
68885
  }
68622
68886
  }
68623
68887
  throw new Error("Unexpected exit from worktree creation retry loop");
@@ -72458,7 +72722,7 @@ function isTickableState(state) {
72458
72722
  function isHeartbeatManaged(agent) {
72459
72723
  return !isEphemeralAgent(agent);
72460
72724
  }
72461
- var HEARTBEAT_SYSTEM_PROMPT, HEARTBEAT_NO_TASK_SYSTEM_PROMPT, HEARTBEAT_PROCEDURE, heartbeatDoneParams, HeartbeatMonitor, OVERDUE_FIRE_JITTER_MS, HeartbeatTriggerScheduler;
72725
+ var HEARTBEAT_SYSTEM_PROMPT, HEARTBEAT_NO_TASK_SYSTEM_PROMPT, HEARTBEAT_PROCEDURE, HEARTBEAT_NO_TASK_PROCEDURE, heartbeatDoneParams, HeartbeatMonitor, OVERDUE_FIRE_JITTER_MS, HeartbeatTriggerScheduler;
72462
72726
  var init_agent_heartbeat = __esm({
72463
72727
  "../engine/src/agent-heartbeat.ts"() {
72464
72728
  "use strict";
@@ -72648,6 +72912,32 @@ When sending messages:
72648
72912
  Critical: a heartbeat without observable progress (a log, a document write, a
72649
72913
  status change, a comment, a delegation, or an explicit "no-op with reason") is
72650
72914
  a bug. Do not loop on the same plan across heartbeats without recording why.`;
72915
+ HEARTBEAT_NO_TASK_PROCEDURE = `## Heartbeat Procedure (run every tick, in order)
72916
+
72917
+ 1. **Identity & context** \u2014 review the **Identity Snapshot** at the top of
72918
+ this prompt. Confirm your role, soul, instructions, and memory match what
72919
+ you expect, and surface any anomalies in your first text output before
72920
+ doing anything else. (If fn_identity is available in your runtime you may
72921
+ also call it for full structured detail; the snapshot above is the
72922
+ authoritative source.)
72923
+ 2. **Inbox** \u2014 when fn_read_messages is available, call it. Process any pending
72924
+ messages first; reply with reply_to_message_id when answering.
72925
+ 3. **Wake delta** \u2014 read the Wake Delta block above. The wake reason is the
72926
+ highest-priority change for this heartbeat. If you were woken by a comment
72927
+ or a message, acknowledge it before doing anything else.
72928
+ 4. **Ambient review** \u2014 since you have no assigned task, review board/project
72929
+ signals and recent memory context before acting.
72930
+ 5. **Pick the next concrete action** \u2014 exactly ONE useful action this heartbeat:
72931
+ create a focused task, delegate work, send/reply to a message, or append
72932
+ durable memory.
72933
+ 6. **Persist progress** \u2014 use available ambient tools only:
72934
+ fn_task_create, fn_delegate_task, fn_send_message, fn_memory_append.
72935
+ 7. **Exit** \u2014 call fn_heartbeat_done with a one-line summary of what changed
72936
+ this tick. If you took no action, say so and explain why.
72937
+
72938
+ Critical: a heartbeat without observable progress (a created task, delegation,
72939
+ message reply, memory append, or explicit "no-op with reason") is a bug. Do
72940
+ not loop on the same plan across heartbeats without recording why.`;
72651
72941
  heartbeatDoneParams = Type6.Object({
72652
72942
  summary: Type6.Optional(Type6.String({ description: "Summary of what was accomplished this heartbeat" }))
72653
72943
  });
@@ -72687,13 +72977,6 @@ a bug. Do not loop on the same plan across heartbeats without recording why.`;
72687
72977
  this.rootDir = options.rootDir;
72688
72978
  this.messageStore = options.messageStore;
72689
72979
  this.pluginRunner = options.pluginRunner;
72690
- this.onRecovered = options.onRecovered;
72691
- this.onTerminated = options.onTerminated;
72692
- this.onRunStarted = options.onRunStarted;
72693
- this.onRunCompleted = options.onRunCompleted;
72694
- this.taskStore = options.taskStore;
72695
- this.rootDir = options.rootDir;
72696
- this.messageStore = options.messageStore;
72697
72980
  }
72698
72981
  /**
72699
72982
  * Start the heartbeat monitoring loop.
@@ -73392,9 +73675,9 @@ a bug. Do not loop on the same plan across heartbeats without recording why.`;
73392
73675
  sourceType: "agent_heartbeat",
73393
73676
  sourceAgentId: agentId,
73394
73677
  sourceRunId: runContext?.runId
73395
- }));
73678
+ }, { rootDir: this.rootDir }));
73396
73679
  heartbeatTools.push(createListAgentsTool(this.store));
73397
- heartbeatTools.push(createDelegateTaskTool(this.store, taskStore));
73680
+ heartbeatTools.push(createDelegateTaskTool(this.store, taskStore, { rootDir: this.rootDir }));
73398
73681
  if (this.messageStore) {
73399
73682
  heartbeatTools.push(createSendMessageTool(this.messageStore, agentId));
73400
73683
  heartbeatTools.push(createReadMessagesTool(this.messageStore, agentId));
@@ -73417,22 +73700,27 @@ a bug. Do not loop on the same plan across heartbeats without recording why.`;
73417
73700
  heartbeatLog.warn(`Failed to configure heartbeat memory tools for ${agentId}: ${message}`);
73418
73701
  }
73419
73702
  const skillContext = buildSessionSkillContextSync2(agent, "heartbeat", rootDir);
73420
- let systemPrompt = isNoTaskRun ? HEARTBEAT_NO_TASK_SYSTEM_PROMPT : HEARTBEAT_SYSTEM_PROMPT;
73421
- const baseHeartbeatSystemPrompt = systemPrompt;
73703
+ const baseHeartbeatSystemPrompt = isNoTaskRun ? HEARTBEAT_NO_TASK_SYSTEM_PROMPT : HEARTBEAT_SYSTEM_PROMPT;
73422
73704
  let resolvedInstructionsForIdentity = "";
73423
73705
  try {
73424
- const agentInstructions = await resolveAgentInstructionsWithRatings(agent, rootDir, this.store);
73425
- resolvedInstructionsForIdentity = agentInstructions;
73426
- const memoryInstructions = memorySettings?.memoryEnabled === false ? "" : buildExecutionMemoryInstructions(rootDir, memorySettings);
73427
- systemPrompt = buildSystemPromptWithInstructions(
73428
- baseHeartbeatSystemPrompt,
73429
- [agentInstructions, memoryInstructions].filter((part) => part.trim()).join("\n\n")
73430
- );
73706
+ resolvedInstructionsForIdentity = await resolveAgentInstructionsWithRatings(agent, rootDir, this.store);
73431
73707
  } catch (instructionError) {
73432
- systemPrompt = baseHeartbeatSystemPrompt;
73433
73708
  const message = instructionError instanceof Error ? instructionError.message : String(instructionError);
73434
- heartbeatLog.warn(`Failed to enrich heartbeat system prompt for ${agentId}: ${message}`);
73709
+ heartbeatLog.warn(`Failed to resolve agent instructions for heartbeat ${agentId}: ${message}`);
73435
73710
  }
73711
+ let memoryInstructions = "";
73712
+ if (memorySettings?.memoryEnabled !== false) {
73713
+ try {
73714
+ memoryInstructions = buildExecutionMemoryInstructions(rootDir, memorySettings);
73715
+ } catch (memoryInstructionErr) {
73716
+ const message = memoryInstructionErr instanceof Error ? memoryInstructionErr.message : String(memoryInstructionErr);
73717
+ heartbeatLog.warn(`Failed to resolve project memory instructions for heartbeat ${agentId}: ${message}`);
73718
+ }
73719
+ }
73720
+ const systemPrompt = buildSystemPromptWithInstructions(
73721
+ baseHeartbeatSystemPrompt,
73722
+ [resolvedInstructionsForIdentity, memoryInstructions].filter((part) => part.trim()).join("\n\n")
73723
+ );
73436
73724
  heartbeatTools.push(createIdentityTool({ agent, resolvedInstructions: resolvedInstructionsForIdentity }));
73437
73725
  heartbeatTools.push(heartbeatDoneTool);
73438
73726
  if (isNoTaskRun) {
@@ -73493,7 +73781,7 @@ a bug. Do not loop on the same plan across heartbeats without recording why.`;
73493
73781
  };
73494
73782
  const wakeReason = deriveWakeReason();
73495
73783
  const customProcedure = await resolveAgentHeartbeatProcedure(agent, rootDir);
73496
- const heartbeatProcedureText = customProcedure ?? HEARTBEAT_PROCEDURE;
73784
+ const heartbeatProcedureText = customProcedure ?? (isNoTaskRun ? HEARTBEAT_NO_TASK_PROCEDURE : HEARTBEAT_PROCEDURE);
73497
73785
  if (isNoTaskRun) {
73498
73786
  if (this.messageStore) {
73499
73787
  try {
@@ -73526,6 +73814,8 @@ a bug. Do not loop on the same plan across heartbeats without recording why.`;
73526
73814
  `- pending messages: ${pendingMessages.length}`,
73527
73815
  "",
73528
73816
  "Treat this wake delta as the highest-priority change for this heartbeat.",
73817
+ "This is an autonomous heartbeat run (manual or automatic): re-anchor on",
73818
+ "identity, process wake context, then complete ONE concrete action.",
73529
73819
  "Run the Heartbeat Procedure (below) before doing anything else \u2014 even a",
73530
73820
  "timer-only wake should re-check messages, memory, and project state.",
73531
73821
  "",
@@ -73617,6 +73907,8 @@ a bug. Do not loop on the same plan across heartbeats without recording why.`;
73617
73907
  `- triggering comments: ${effectiveTriggeringCommentIds?.length ?? 0}`,
73618
73908
  "",
73619
73909
  "Treat this wake delta as the highest-priority change for this heartbeat.",
73910
+ "This is an autonomous heartbeat run (manual or automatic): re-anchor on",
73911
+ "identity, process wake context, then complete ONE concrete action.",
73620
73912
  "Before resuming prior task work, run the Heartbeat Procedure (below) and",
73621
73913
  "decide what action this delta requires. Your assigned task is one input",
73622
73914
  "to the procedure \u2014 not the only thing to consider.",
@@ -73776,7 +74068,7 @@ ${taskDetail.prompt}` : "No PROMPT.md available.",
73776
74068
  const baseCreateTool = createTaskCreateTool(taskStore, {
73777
74069
  sourceType: "agent_heartbeat",
73778
74070
  sourceAgentId: agentId
73779
- });
74071
+ }, { rootDir: this.rootDir });
73780
74072
  const trackedCreateTool = {
73781
74073
  ...baseCreateTool,
73782
74074
  execute: async (id, params, signal, onUpdate, ctx) => {
@@ -73803,7 +74095,7 @@ ${taskDetail.prompt}` : "No PROMPT.md available.",
73803
74095
  tools.push(createTaskDocumentWriteTool(taskStore, taskId));
73804
74096
  tools.push(createTaskDocumentReadTool(taskStore, taskId));
73805
74097
  tools.push(createListAgentsTool(this.store));
73806
- tools.push(createDelegateTaskTool(this.store, taskStore));
74098
+ tools.push(createDelegateTaskTool(this.store, taskStore, { rootDir: this.rootDir }));
73807
74099
  if (messageStore) {
73808
74100
  tools.push(createSendMessageTool(messageStore, agentId));
73809
74101
  tools.push(createReadMessagesTool(messageStore, agentId));
@@ -75387,7 +75679,7 @@ var init_shell_utils = __esm({
75387
75679
  // ../engine/src/cron-runner.ts
75388
75680
  import { exec as exec6 } from "node:child_process";
75389
75681
  function execCommand(command, options) {
75390
- return new Promise((resolve40, reject2) => {
75682
+ return new Promise((resolve42, reject2) => {
75391
75683
  exec6(command, options, (error, stdout, stderr) => {
75392
75684
  const stdoutText = typeof stdout === "string" ? stdout : String(stdout ?? "");
75393
75685
  const stderrText = typeof stderr === "string" ? stderr : String(stderr ?? "");
@@ -75398,7 +75690,7 @@ function execCommand(command, options) {
75398
75690
  reject2(errWithOutput);
75399
75691
  return;
75400
75692
  }
75401
- resolve40({ stdout: stdoutText, stderr: stderrText });
75693
+ resolve42({ stdout: stdoutText, stderr: stderrText });
75402
75694
  });
75403
75695
  });
75404
75696
  }
@@ -78749,13 +79041,13 @@ var init_plugin_runner = __esm({
78749
79041
  * Returns the result on success, throws on timeout.
78750
79042
  */
78751
79043
  withTimeout(promise, ms, timeoutMessage) {
78752
- return new Promise((resolve40, reject2) => {
79044
+ return new Promise((resolve42, reject2) => {
78753
79045
  const timer = setTimeout(() => {
78754
79046
  reject2(new Error(timeoutMessage));
78755
79047
  }, ms);
78756
79048
  promise.then((result) => {
78757
79049
  clearTimeout(timer);
78758
- resolve40(result);
79050
+ resolve42(result);
78759
79051
  }).catch((err) => {
78760
79052
  clearTimeout(timer);
78761
79053
  reject2(err);
@@ -79391,7 +79683,7 @@ var init_in_process_runtime = __esm({
79391
79683
  runtimeLog.log(
79392
79684
  `Waiting for ${metrics.inFlightTasks} in-flight tasks to complete...`
79393
79685
  );
79394
- await new Promise((resolve40) => setTimeout(resolve40, 1e3));
79686
+ await new Promise((resolve42) => setTimeout(resolve42, 1e3));
79395
79687
  }
79396
79688
  const finalMetrics = this.getMetrics();
79397
79689
  if (finalMetrics.inFlightTasks > 0) {
@@ -79788,13 +80080,13 @@ var init_ipc_host = __esm({
79788
80080
  }
79789
80081
  const id = generateCorrelationId();
79790
80082
  const message = { type, id, payload };
79791
- return new Promise((resolve40, reject2) => {
80083
+ return new Promise((resolve42, reject2) => {
79792
80084
  const timeout2 = setTimeout(() => {
79793
80085
  this.pendingCommands.delete(id);
79794
80086
  reject2(new Error(`Command ${type} timed out after ${timeoutMs ?? this.commandTimeoutMs}ms`));
79795
80087
  }, timeoutMs ?? this.commandTimeoutMs);
79796
80088
  this.pendingCommands.set(id, {
79797
- resolve: resolve40,
80089
+ resolve: resolve42,
79798
80090
  reject: reject2,
79799
80091
  timeout: timeout2,
79800
80092
  type
@@ -80603,8 +80895,8 @@ var init_remote_node_client = __esm({
80603
80895
  return error instanceof TypeError;
80604
80896
  }
80605
80897
  async sleep(ms) {
80606
- await new Promise((resolve40) => {
80607
- setTimeout(resolve40, ms);
80898
+ await new Promise((resolve42) => {
80899
+ setTimeout(resolve42, ms);
80608
80900
  });
80609
80901
  }
80610
80902
  };
@@ -80868,14 +81160,14 @@ var init_remote_node_runtime = __esm({
80868
81160
  return error instanceof Error ? error : new Error(String(error));
80869
81161
  }
80870
81162
  async sleep(ms, signal) {
80871
- await new Promise((resolve40) => {
81163
+ await new Promise((resolve42) => {
80872
81164
  const timeout2 = setTimeout(() => {
80873
81165
  cleanup();
80874
- resolve40();
81166
+ resolve42();
80875
81167
  }, ms);
80876
81168
  const onAbort = () => {
80877
81169
  cleanup();
80878
- resolve40();
81170
+ resolve42();
80879
81171
  };
80880
81172
  const cleanup = () => {
80881
81173
  clearTimeout(timeout2);
@@ -81505,7 +81797,7 @@ var init_provider_adapters = __esm({
81505
81797
 
81506
81798
  // ../engine/src/remote-access/tunnel-process-manager.ts
81507
81799
  import { EventEmitter as EventEmitter24 } from "node:events";
81508
- import { exec as exec9, execFile as execFile3, spawn as spawn4 } from "node:child_process";
81800
+ import { exec as exec9, execFile as execFile3, spawn as spawn5 } from "node:child_process";
81509
81801
  import { promisify as promisify9 } from "node:util";
81510
81802
  function nowIso() {
81511
81803
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -81596,7 +81888,7 @@ var init_tunnel_process_manager = __esm({
81596
81888
  super();
81597
81889
  this.maxLogEntries = options.maxLogEntries ?? DEFAULT_MAX_LOG_ENTRIES;
81598
81890
  this.defaultStopTimeoutMs = options.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS2;
81599
- this.spawnImpl = options.spawnImpl ?? spawn4;
81891
+ this.spawnImpl = options.spawnImpl ?? spawn5;
81600
81892
  }
81601
81893
  getStatus() {
81602
81894
  return { ...this.status, lastError: this.status.lastError ? { ...this.status.lastError } : null };
@@ -81826,10 +82118,10 @@ var init_tunnel_process_manager = __esm({
81826
82118
  lastError: null
81827
82119
  });
81828
82120
  this.emitLog("info", "manager", `Stopping ${currentHandle.provider} tunnel (pid=${currentHandle.child.pid ?? "n/a"})`);
81829
- this.activeStopPromise = new Promise((resolve40) => {
82121
+ this.activeStopPromise = new Promise((resolve42) => {
81830
82122
  const onClose = () => {
81831
82123
  currentHandle.child.removeListener("close", onClose);
81832
- resolve40();
82124
+ resolve42();
81833
82125
  };
81834
82126
  currentHandle.child.once("close", onClose);
81835
82127
  killManagedProcess(currentHandle.child, "SIGTERM");
@@ -81970,6 +82262,7 @@ var execFileAsync2, MERGE_HANDOFF_GRACE_MS, isRemoteActive, ProjectEngine;
81970
82262
  var init_project_engine = __esm({
81971
82263
  "../engine/src/project-engine.ts"() {
81972
82264
  "use strict";
82265
+ init_src();
81973
82266
  init_in_process_runtime();
81974
82267
  init_pr_monitor();
81975
82268
  init_pr_comment_handler();
@@ -82436,12 +82729,12 @@ ${detail}`
82436
82729
  */
82437
82730
  async onMerge(taskId) {
82438
82731
  if (this.mergeActive.has(taskId)) {
82439
- return new Promise((resolve40, reject2) => {
82440
- this.manualMergeResolvers.set(taskId, { resolve: resolve40, reject: reject2 });
82732
+ return new Promise((resolve42, reject2) => {
82733
+ this.manualMergeResolvers.set(taskId, { resolve: resolve42, reject: reject2 });
82441
82734
  });
82442
82735
  }
82443
- return new Promise((resolve40, reject2) => {
82444
- this.manualMergeResolvers.set(taskId, { resolve: resolve40, reject: reject2 });
82736
+ return new Promise((resolve42, reject2) => {
82737
+ this.manualMergeResolvers.set(taskId, { resolve: resolve42, reject: reject2 });
82445
82738
  this.internalEnqueueMerge(taskId);
82446
82739
  });
82447
82740
  }
@@ -82664,6 +82957,48 @@ ${detail}`
82664
82957
  if (task.status === "failed") return false;
82665
82958
  return (task.mergeRetries ?? 0) < _ProjectEngine.MAX_AUTO_MERGE_RETRIES || this.hasAutoHealableVerificationBufferFailure(task) || this.isRetryCooldownElapsed(task);
82666
82959
  }
82960
+ /**
82961
+ * Remove and return the highest-priority taskId from the merge queue.
82962
+ * Ordering: priority (urgent→low), then createdAt ASC, then id ASC — matching
82963
+ * the triage and scheduler comparators. Manual merges (onMerge resolvers) are
82964
+ * preferred over auto-merges so awaited callers aren't starved by a flood of
82965
+ * higher-priority auto-enqueues. IDs whose tasks can't be loaded fall back to
82966
+ * FIFO order so they still drain.
82967
+ */
82968
+ async pickNextMergeTaskId(store) {
82969
+ if (this.mergeQueue.length === 0) return void 0;
82970
+ if (this.mergeQueue.length === 1) {
82971
+ return this.mergeQueue.shift();
82972
+ }
82973
+ const queueSnapshot = [...this.mergeQueue];
82974
+ const entries = [];
82975
+ for (let i = 0; i < queueSnapshot.length; i++) {
82976
+ const taskId = queueSnapshot[i];
82977
+ const task = await store.getTask(taskId).catch(() => void 0);
82978
+ entries.push({
82979
+ taskId,
82980
+ task,
82981
+ manual: this.manualMergeResolvers.has(taskId),
82982
+ order: i
82983
+ });
82984
+ }
82985
+ if (this.shuttingDown) return void 0;
82986
+ entries.sort((a, b) => {
82987
+ if (a.manual !== b.manual) return a.manual ? -1 : 1;
82988
+ if (a.task && b.task) return compareTasksByPriorityThenAgeAndId(a.task, b.task);
82989
+ if (a.task) return -1;
82990
+ if (b.task) return 1;
82991
+ return a.order - b.order;
82992
+ });
82993
+ for (const entry of entries) {
82994
+ const liveIndex = this.mergeQueue.indexOf(entry.taskId);
82995
+ if (liveIndex !== -1) {
82996
+ this.mergeQueue.splice(liveIndex, 1);
82997
+ return entry.taskId;
82998
+ }
82999
+ }
83000
+ return void 0;
83001
+ }
82667
83002
  internalEnqueueMerge(taskId) {
82668
83003
  if (this.shuttingDown) return;
82669
83004
  if (this.mergeActive.has(taskId)) return;
@@ -82671,6 +83006,23 @@ ${detail}`
82671
83006
  this.mergeQueue.push(taskId);
82672
83007
  void this.drainMergeQueue();
82673
83008
  }
83009
+ /**
83010
+ * Filter a sweep's listTasks() result to merge-eligible tasks, sort by
83011
+ * priority (urgent → low, then createdAt ASC, then id ASC), and enqueue.
83012
+ * Sorting before enqueue matters because each enqueue may immediately
83013
+ * trigger drainMergeQueue's single-item fast path, so the first task
83014
+ * pushed wins. listTasks returns createdAt ASC — without this sort an
83015
+ * older low-priority task would start before a later urgent one.
83016
+ */
83017
+ enqueueEligibleInReviewTasks(tasks) {
83018
+ const eligible = sortTasksByPriorityThenAgeAndId(
83019
+ tasks.filter((t) => !t.paused && this.canMergeTask(t))
83020
+ );
83021
+ for (const t of eligible) {
83022
+ this.internalEnqueueMerge(t.id);
83023
+ }
83024
+ return eligible.length;
83025
+ }
82674
83026
  async drainMergeQueue() {
82675
83027
  if (this.mergeRunning) return;
82676
83028
  this.mergeRunning = true;
@@ -82678,7 +83030,9 @@ ${detail}`
82678
83030
  const store = this.runtime.getTaskStore();
82679
83031
  const cwd = this.config.workingDirectory;
82680
83032
  while (this.mergeQueue.length > 0 && !this.shuttingDown) {
82681
- const taskId = this.mergeQueue.shift();
83033
+ const taskId = await this.pickNextMergeTaskId(store);
83034
+ if (!taskId) break;
83035
+ if (this.shuttingDown) break;
82682
83036
  const manualResolver = this.manualMergeResolvers.get(taskId);
82683
83037
  try {
82684
83038
  if (!manualResolver) {
@@ -83148,12 +83502,9 @@ ${detail}`
83148
83502
  }
83149
83503
  const settings = await store.getSettings();
83150
83504
  if (!settings.autoMerge) return;
83151
- const eligible = tasks.filter((t) => !t.paused && this.canMergeTask(t));
83152
- if (eligible.length > 0) {
83153
- runtimeLog.log(`Auto-merge startup sweep: enqueueing ${eligible.length} task(s)`);
83154
- for (const t of eligible) {
83155
- this.internalEnqueueMerge(t.id);
83156
- }
83505
+ const enqueued = this.enqueueEligibleInReviewTasks(tasks);
83506
+ if (enqueued > 0) {
83507
+ runtimeLog.log(`Auto-merge startup sweep: enqueueing ${enqueued} task(s)`);
83157
83508
  }
83158
83509
  } catch (err) {
83159
83510
  runtimeLog.warn(
@@ -83169,14 +83520,7 @@ ${detail}`
83169
83520
  const settings = await store.getSettings();
83170
83521
  if (!settings.globalPause && !settings.enginePaused && settings.autoMerge) {
83171
83522
  const tasks = await store.listTasks({ column: "in-review" });
83172
- for (const t of tasks) {
83173
- if (t.paused) {
83174
- continue;
83175
- }
83176
- if (this.canMergeTask(t)) {
83177
- this.internalEnqueueMerge(t.id);
83178
- }
83179
- }
83523
+ this.enqueueEligibleInReviewTasks(tasks);
83180
83524
  }
83181
83525
  } catch (err) {
83182
83526
  runtimeLog.warn(
@@ -83232,14 +83576,7 @@ ${detail}`
83232
83576
  if (s.autoMerge) {
83233
83577
  try {
83234
83578
  const tasks = await store.listTasks({ column: "in-review" });
83235
- for (const t of tasks) {
83236
- if (t.paused) {
83237
- continue;
83238
- }
83239
- if (this.canMergeTask(t)) {
83240
- this.internalEnqueueMerge(t.id);
83241
- }
83242
- }
83579
+ this.enqueueEligibleInReviewTasks(tasks);
83243
83580
  } catch (err) {
83244
83581
  runtimeLog.warn(
83245
83582
  `Global unpause: failed to scan in-review tasks for auto-merge: ${err instanceof Error ? err.message : String(err)}`
@@ -83269,14 +83606,7 @@ ${detail}`
83269
83606
  if (s.autoMerge) {
83270
83607
  try {
83271
83608
  const tasks = await store.listTasks({ column: "in-review" });
83272
- for (const t of tasks) {
83273
- if (t.paused) {
83274
- continue;
83275
- }
83276
- if (this.canMergeTask(t)) {
83277
- this.internalEnqueueMerge(t.id);
83278
- }
83279
- }
83609
+ this.enqueueEligibleInReviewTasks(tasks);
83280
83610
  } catch (err) {
83281
83611
  runtimeLog.warn(
83282
83612
  `Engine unpause: failed to scan in-review tasks for auto-merge: ${err instanceof Error ? err.message : String(err)}`
@@ -83869,7 +84199,7 @@ var init_peer_exchange_service = __esm({
83869
84199
  syncIntervalMs;
83870
84200
  interval = null;
83871
84201
  activeSync = null;
83872
- stopped = false;
84202
+ running = false;
83873
84203
  /** Whether settings sync is enabled. Default: false. */
83874
84204
  settingsSyncEnabled;
83875
84205
  /** Minimum interval between settings syncs with the same node in ms. Default: 5 minutes. */
@@ -83911,10 +84241,11 @@ var init_peer_exchange_service = __esm({
83911
84241
  * Begins periodic gossip with all online remote nodes.
83912
84242
  */
83913
84243
  start() {
83914
- if (this.stopped) {
83915
- peerExchangeLog.warn("Cannot start - service has been stopped");
84244
+ if (this.running) {
84245
+ peerExchangeLog.log("Peer exchange service already running");
83916
84246
  return;
83917
84247
  }
84248
+ this.running = true;
83918
84249
  this.centralCore.listNodes().then((nodes) => {
83919
84250
  const onlineRemoteCount = nodes.filter(
83920
84251
  (n) => n.type === "remote" && n.status === "online" && n.url
@@ -83924,6 +84255,7 @@ var init_peer_exchange_service = __esm({
83924
84255
  peerExchangeLog.warn(`Failed to get initial peer count: ${err}`);
83925
84256
  });
83926
84257
  this.interval = setInterval(() => {
84258
+ if (!this.running) return;
83927
84259
  void this.syncWithAllPeers();
83928
84260
  }, this.syncIntervalMs);
83929
84261
  }
@@ -83931,12 +84263,21 @@ var init_peer_exchange_service = __esm({
83931
84263
  * Stop the peer exchange service.
83932
84264
  * Clears the sync interval and prevents further syncs.
83933
84265
  */
83934
- stop() {
84266
+ async stop() {
84267
+ if (!this.running) {
84268
+ return;
84269
+ }
84270
+ this.running = false;
83935
84271
  if (this.interval) {
83936
84272
  clearInterval(this.interval);
83937
84273
  this.interval = null;
83938
84274
  }
83939
- this.stopped = true;
84275
+ if (this.activeSync) {
84276
+ try {
84277
+ await this.activeSync;
84278
+ } catch {
84279
+ }
84280
+ }
83940
84281
  peerExchangeLog.log("Stopped peer exchange service");
83941
84282
  }
83942
84283
  /**
@@ -85495,7 +85836,7 @@ For completion:
85495
85836
  }`;
85496
85837
  SESSION_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
85497
85838
  CLEANUP_INTERVAL_MS2 = 5 * 60 * 1e3;
85498
- MAX_SESSIONS_PER_IP_PER_HOUR = 5;
85839
+ MAX_SESSIONS_PER_IP_PER_HOUR = 1e3;
85499
85840
  RATE_LIMIT_WINDOW_MS2 = 60 * 60 * 1e3;
85500
85841
  GENERATION_TIMEOUT_MS = 12e4;
85501
85842
  sessions = /* @__PURE__ */ new Map();
@@ -88381,7 +88722,7 @@ var init_src3 = __esm({
88381
88722
  });
88382
88723
 
88383
88724
  // ../../plugins/fusion-plugin-hermes-runtime/dist/cli-spawn.js
88384
- import { spawn as spawn5, spawnSync } from "node:child_process";
88725
+ import { spawn as spawn6, spawnSync } from "node:child_process";
88385
88726
  import os2 from "node:os";
88386
88727
  import path, { sep as PATH_SEP } from "node:path";
88387
88728
  function resolveBinaryForSpawn(binary) {
@@ -88443,9 +88784,9 @@ function hermesProfileHome(profileName) {
88443
88784
  async function listHermesProfiles(opts) {
88444
88785
  const binary = resolveBinaryForSpawn(opts?.binaryPath ?? "hermes");
88445
88786
  const timeoutMs = opts?.timeoutMs ?? 5e3;
88446
- return new Promise((resolve40, reject2) => {
88787
+ return new Promise((resolve42, reject2) => {
88447
88788
  let settled = false;
88448
- const child = spawn5(binary, ["profile", "list"], {
88789
+ const child = spawn6(binary, ["profile", "list"], {
88449
88790
  stdio: ["ignore", "pipe", "pipe"],
88450
88791
  env: { ...process.env }
88451
88792
  });
@@ -88486,7 +88827,7 @@ async function listHermesProfiles(opts) {
88486
88827
  ${combined}`));
88487
88828
  return;
88488
88829
  }
88489
- resolve40(parseProfileListOutput(stdout));
88830
+ resolve42(parseProfileListOutput(stdout));
88490
88831
  });
88491
88832
  });
88492
88833
  }
@@ -88563,13 +88904,13 @@ function buildHermesArgs(prompt, settings, resumeSessionId) {
88563
88904
  async function invokeHermesCli(prompt, settings, resumeSessionId, signal) {
88564
88905
  const args = buildHermesArgs(prompt, settings, resumeSessionId);
88565
88906
  const binary = resolveBinaryForSpawn(settings.binaryPath);
88566
- return new Promise((resolve40, reject2) => {
88907
+ return new Promise((resolve42, reject2) => {
88567
88908
  let settled = false;
88568
88909
  const spawnEnv = { ...process.env, PYTHONUNBUFFERED: "1" };
88569
88910
  if (settings.profile) {
88570
88911
  spawnEnv.HERMES_HOME = hermesProfileHome(settings.profile);
88571
88912
  }
88572
- const child = spawn5(binary, args, {
88913
+ const child = spawn6(binary, args, {
88573
88914
  stdio: ["ignore", "pipe", "pipe"],
88574
88915
  env: spawnEnv
88575
88916
  });
@@ -88631,7 +88972,7 @@ ${combined}`));
88631
88972
  return;
88632
88973
  }
88633
88974
  try {
88634
- resolve40(parseHermesOutput(stdout, stderr));
88975
+ resolve42(parseHermesOutput(stdout, stderr));
88635
88976
  } catch (parseErr) {
88636
88977
  reject2(parseErr);
88637
88978
  }
@@ -88724,7 +89065,7 @@ var init_runtime_adapter = __esm({
88724
89065
  });
88725
89066
 
88726
89067
  // ../../plugins/fusion-plugin-hermes-runtime/dist/probe.js
88727
- import { spawn as spawn6 } from "node:child_process";
89068
+ import { spawn as spawn7 } from "node:child_process";
88728
89069
  async function probeHermesBinary(opts) {
88729
89070
  const startedAt = Date.now();
88730
89071
  const binary = typeof opts?.binaryPath === "string" && opts.binaryPath.trim().length > 0 ? opts.binaryPath.trim() : "hermes";
@@ -88735,7 +89076,7 @@ async function probeHermesBinary(opts) {
88735
89076
  resolvePromise({ ...result, probeDurationMs: Date.now() - startedAt });
88736
89077
  };
88737
89078
  let settled = false;
88738
- const child = spawn6(resolvedPath ?? binary, ["--version"], {
89079
+ const child = spawn7(resolvedPath ?? binary, ["--version"], {
88739
89080
  stdio: ["ignore", "pipe", "pipe"]
88740
89081
  });
88741
89082
  const timer = setTimeout(() => {
@@ -88796,7 +89137,7 @@ async function probeHermesBinary(opts) {
88796
89137
  async function tryResolveBinaryPath(binary) {
88797
89138
  return new Promise((resolvePromise) => {
88798
89139
  const which = process.platform === "win32" ? "where" : "which";
88799
- const child = spawn6(which, [binary], { stdio: ["ignore", "pipe", "ignore"] });
89140
+ const child = spawn7(which, [binary], { stdio: ["ignore", "pipe", "ignore"] });
88800
89141
  let out = "";
88801
89142
  child.stdout?.on("data", (chunk) => {
88802
89143
  out += chunk.toString("utf-8");
@@ -88874,7 +89215,7 @@ var init_dist = __esm({
88874
89215
  });
88875
89216
 
88876
89217
  // ../../plugins/fusion-plugin-openclaw-runtime/dist/pi-module.js
88877
- import { spawn as spawn7 } from "node:child_process";
89218
+ import { spawn as spawn8 } from "node:child_process";
88878
89219
  import { randomUUID as randomUUID15 } from "node:crypto";
88879
89220
  function asString(v) {
88880
89221
  return typeof v === "string" && v.trim() !== "" ? v.trim() : void 0;
@@ -88949,9 +89290,9 @@ async function promptCli(session, message, config, callbacks, signal) {
88949
89290
  const args = buildOpenClawArgs(config, session.sessionId, message);
88950
89291
  const cb = { ...session.callbacks, ...callbacks };
88951
89292
  cb.onToolStart?.("openclaw.agent", { sessionId: session.sessionId });
88952
- return new Promise((resolve40, reject2) => {
89293
+ return new Promise((resolve42, reject2) => {
88953
89294
  let settled = false;
88954
- const child = spawn7(config.binaryPath, args, {
89295
+ const child = spawn8(config.binaryPath, args, {
88955
89296
  stdio: ["ignore", "pipe", "pipe"]
88956
89297
  });
88957
89298
  const hardKill = setTimeout(() => {
@@ -89042,7 +89383,7 @@ async function promptCli(session, message, config, callbacks, signal) {
89042
89383
  ...metaError ? { error: metaError } : {},
89043
89384
  ...errorText.length > 0 ? { toolErrors: errorText } : {}
89044
89385
  });
89045
- resolve40();
89386
+ resolve42();
89046
89387
  });
89047
89388
  });
89048
89389
  }
@@ -89102,7 +89443,7 @@ var init_runtime_adapter2 = __esm({
89102
89443
  });
89103
89444
 
89104
89445
  // ../../plugins/fusion-plugin-openclaw-runtime/dist/probe.js
89105
- import { spawn as spawn8 } from "node:child_process";
89446
+ import { spawn as spawn9 } from "node:child_process";
89106
89447
  async function probeOpenClawBinary(opts = {}) {
89107
89448
  const startedAt = Date.now();
89108
89449
  const binary = opts.binaryPath ?? "openclaw";
@@ -89113,7 +89454,7 @@ async function probeOpenClawBinary(opts = {}) {
89113
89454
  resolvePromise({ ...partial, probeDurationMs: Date.now() - startedAt });
89114
89455
  };
89115
89456
  let settled = false;
89116
- const child = spawn8(resolvedPath ?? binary, ["--version"], {
89457
+ const child = spawn9(resolvedPath ?? binary, ["--version"], {
89117
89458
  stdio: ["ignore", "pipe", "pipe"]
89118
89459
  });
89119
89460
  const timer = setTimeout(() => {
@@ -89174,7 +89515,7 @@ async function probeOpenClawBinary(opts = {}) {
89174
89515
  async function tryResolveBinaryPath2(binary) {
89175
89516
  return new Promise((resolvePromise) => {
89176
89517
  const which = process.platform === "win32" ? "where" : "which";
89177
- const child = spawn8(which, [binary], { stdio: ["ignore", "pipe", "ignore"] });
89518
+ const child = spawn9(which, [binary], { stdio: ["ignore", "pipe", "ignore"] });
89178
89519
  let out = "";
89179
89520
  child.stdout?.on("data", (chunk) => {
89180
89521
  out += chunk.toString("utf-8");
@@ -90595,7 +90936,7 @@ function registerTaskWorkflowRoutes(ctx, deps) {
90595
90936
  router.patch("/tasks/:id", async (req, res) => {
90596
90937
  try {
90597
90938
  const { store: scopedStore } = await getProjectContext3(req);
90598
- const { title, description, prompt, dependencies, enabledWorkflowSteps, modelProvider, modelId, validatorModelProvider, validatorModelId, planningModelProvider, planningModelId, thinkingLevel, assigneeUserId, reviewLevel, executionMode, sourceIssue, nodeId } = req.body;
90939
+ const { title, description, prompt, priority, dependencies, enabledWorkflowSteps, modelProvider, modelId, validatorModelProvider, validatorModelId, planningModelProvider, planningModelId, thinkingLevel, assigneeUserId, reviewLevel, executionMode, sourceIssue, nodeId } = req.body;
90599
90940
  const hasBodyField = (field) => Object.prototype.hasOwnProperty.call(req.body, field);
90600
90941
  const validateModelField = (value, name) => {
90601
90942
  if (value === void 0) return void 0;
@@ -90625,6 +90966,9 @@ function registerTaskWorkflowRoutes(ctx, deps) {
90625
90966
  if (executionMode !== void 0 && executionMode !== null && !validExecutionModes.includes(executionMode)) {
90626
90967
  throw new Error(`executionMode must be one of: ${validExecutionModes.join(", ")}`);
90627
90968
  }
90969
+ if (priority !== void 0 && priority !== null && !isTaskPriority(priority)) {
90970
+ throw new Error(`priority must be one of: ${TASK_PRIORITIES.join(", ")}`);
90971
+ }
90628
90972
  if (enabledWorkflowSteps !== void 0) {
90629
90973
  if (!Array.isArray(enabledWorkflowSteps) || !enabledWorkflowSteps.every((id) => typeof id === "string")) {
90630
90974
  throw new Error("enabledWorkflowSteps must be an array of strings");
@@ -90684,6 +91028,7 @@ function registerTaskWorkflowRoutes(ctx, deps) {
90684
91028
  if (title !== void 0) updates.title = title;
90685
91029
  if (description !== void 0) updates.description = description;
90686
91030
  if (prompt !== void 0) updates.prompt = prompt;
91031
+ if (hasBodyField("priority")) updates.priority = priority;
90687
91032
  if (dependencies !== void 0) updates.dependencies = dependencies;
90688
91033
  if (enabledWorkflowSteps !== void 0) updates.enabledWorkflowSteps = enabledWorkflowSteps;
90689
91034
  if (hasBodyField("modelProvider")) updates.modelProvider = validatedModelProvider;
@@ -90714,7 +91059,7 @@ function registerTaskWorkflowRoutes(ctx, deps) {
90714
91059
  if (err instanceof ApiError) {
90715
91060
  throw err;
90716
91061
  }
90717
- const status = (err instanceof Error ? err.message : String(err)).includes("must be a string") || (err instanceof Error ? err.message : String(err)).includes("must be a non-empty string") || (err instanceof Error ? err.message : String(err)).includes("must be a string or null") || (err instanceof Error ? err.message : String(err)).includes("must be an array of strings") || (err instanceof Error ? err.message : String(err)).includes("thinkingLevel must be one of") || (err instanceof Error ? err.message : String(err)).includes("reviewLevel must be an integer") || (err instanceof Error ? err.message : String(err)).includes("executionMode must be one of") || (err instanceof Error ? err.message : String(err)).includes("sourceIssue") ? 400 : 500;
91062
+ const status = (err instanceof Error ? err.message : String(err)).includes("must be a string") || (err instanceof Error ? err.message : String(err)).includes("must be a non-empty string") || (err instanceof Error ? err.message : String(err)).includes("must be a string or null") || (err instanceof Error ? err.message : String(err)).includes("must be an array of strings") || (err instanceof Error ? err.message : String(err)).includes("thinkingLevel must be one of") || (err instanceof Error ? err.message : String(err)).includes("reviewLevel must be an integer") || (err instanceof Error ? err.message : String(err)).includes("executionMode must be one of") || (err instanceof Error ? err.message : String(err)).includes("priority must be one of") || (err instanceof Error ? err.message : String(err)).includes("sourceIssue") ? 400 : 500;
90718
91063
  throw new ApiError(status, err instanceof Error ? err.message : String(err));
90719
91064
  }
90720
91065
  });
@@ -97386,10 +97731,10 @@ var require_browser3 = __commonJS({
97386
97731
  text = canvas;
97387
97732
  canvas = void 0;
97388
97733
  }
97389
- return new Promise(function(resolve40, reject2) {
97734
+ return new Promise(function(resolve42, reject2) {
97390
97735
  try {
97391
97736
  const data = QRCode2.create(text, opts);
97392
- resolve40(renderFunc(data, canvas, opts));
97737
+ resolve42(renderFunc(data, canvas, opts));
97393
97738
  } catch (e) {
97394
97739
  reject2(e);
97395
97740
  }
@@ -97471,11 +97816,11 @@ var require_server = __commonJS({
97471
97816
  }
97472
97817
  function render(renderFunc, text, params) {
97473
97818
  if (!params.cb) {
97474
- return new Promise(function(resolve40, reject2) {
97819
+ return new Promise(function(resolve42, reject2) {
97475
97820
  try {
97476
97821
  const data = QRCode2.create(text, params.opts);
97477
97822
  return renderFunc(data, params.opts, function(err, data2) {
97478
- return err ? reject2(err) : resolve40(data2);
97823
+ return err ? reject2(err) : resolve42(data2);
97479
97824
  });
97480
97825
  } catch (e) {
97481
97826
  reject2(e);
@@ -99123,9 +99468,9 @@ import * as fs2 from "node:fs";
99123
99468
  import { createRequire as createRequire3 } from "node:module";
99124
99469
  import { join as join42, dirname as dirname12 } from "node:path";
99125
99470
  function getNativePrebuildName() {
99126
- const platform3 = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : process.platform === "win32" ? "win32" : "unknown";
99471
+ const platform4 = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : process.platform === "win32" ? "win32" : "unknown";
99127
99472
  const arch = process.arch === "arm64" ? "arm64" : process.arch === "x64" ? "x64" : "unknown";
99128
- return `${platform3}-${arch}`;
99473
+ return `${platform4}-${arch}`;
99129
99474
  }
99130
99475
  function findInstalledNodePtyNativeDir() {
99131
99476
  try {
@@ -99307,8 +99652,8 @@ var init_terminal_service = __esm({
99307
99652
  * Get the default allowed shells for the current platform
99308
99653
  */
99309
99654
  getAllowedShells() {
99310
- const platform3 = os3.platform();
99311
- return ALLOWED_SHELL_PATHS[platform3] || ALLOWED_SHELL_PATHS.linux;
99655
+ const platform4 = os3.platform();
99656
+ return ALLOWED_SHELL_PATHS[platform4] || ALLOWED_SHELL_PATHS.linux;
99312
99657
  }
99313
99658
  /**
99314
99659
  * Validate that a shell path is allowed
@@ -99322,7 +99667,7 @@ var init_terminal_service = __esm({
99322
99667
  * Detect the best shell for the current platform
99323
99668
  */
99324
99669
  detectShell() {
99325
- const platform3 = os3.platform();
99670
+ const platform4 = os3.platform();
99326
99671
  const allowedShells = this.getAllowedShells();
99327
99672
  const getBasename = (shellPath) => {
99328
99673
  const lastSep = Math.max(shellPath.lastIndexOf("/"), shellPath.lastIndexOf("\\"));
@@ -99339,7 +99684,7 @@ var init_terminal_service = __esm({
99339
99684
  return ["--login"];
99340
99685
  };
99341
99686
  const userShell = process.env.SHELL;
99342
- if (userShell && platform3 !== "win32") {
99687
+ if (userShell && platform4 !== "win32") {
99343
99688
  const normalizedUserShell = this.isWindows ? userShell.toLowerCase() : userShell;
99344
99689
  for (const allowed of allowedShells) {
99345
99690
  const normalizedAllowed = this.isWindows ? allowed.toLowerCase() : allowed;
@@ -99353,7 +99698,7 @@ var init_terminal_service = __esm({
99353
99698
  return { shell, args: getShellArgs(shell) };
99354
99699
  }
99355
99700
  }
99356
- if (platform3 === "win32") {
99701
+ if (platform4 === "win32") {
99357
99702
  return { shell: "cmd.exe", args: [] };
99358
99703
  }
99359
99704
  return { shell: "/bin/sh", args: [] };
@@ -100186,7 +100531,7 @@ var init_register_messaging_scripts = __esm({
100186
100531
 
100187
100532
  // ../dashboard/src/github.ts
100188
100533
  function delay(ms) {
100189
- return new Promise((resolve40) => setTimeout(resolve40, ms));
100534
+ return new Promise((resolve42) => setTimeout(resolve42, ms));
100190
100535
  }
100191
100536
  function normalizeCheckState(state) {
100192
100537
  switch ((state ?? "").toLowerCase()) {
@@ -104580,7 +104925,7 @@ var init_register_git_github = __esm({
104580
104925
  });
104581
104926
 
104582
104927
  // ../dashboard/src/terminal.ts
104583
- import { spawn as spawn9 } from "node:child_process";
104928
+ import { spawn as spawn10 } from "node:child_process";
104584
104929
  import { randomUUID as randomUUID17 } from "node:crypto";
104585
104930
  import { EventEmitter as EventEmitter32 } from "node:events";
104586
104931
  function extractBaseCommand(command) {
@@ -104742,7 +105087,7 @@ var init_terminal = __esm({
104742
105087
  return { sessionId: "", error: validation.error };
104743
105088
  }
104744
105089
  const sessionId = randomUUID17();
104745
- const childProcess = spawn9(command, [], {
105090
+ const childProcess = spawn10(command, [], {
104746
105091
  cwd,
104747
105092
  shell: true,
104748
105093
  stdio: ["pipe", "pipe", "pipe"],
@@ -106460,9 +106805,9 @@ var require_readdir_glob = __commonJS({
106460
106805
  var fs3 = __require("fs");
106461
106806
  var { EventEmitter: EventEmitter37 } = __require("events");
106462
106807
  var { Minimatch } = require_minimatch();
106463
- var { resolve: resolve40 } = __require("path");
106808
+ var { resolve: resolve42 } = __require("path");
106464
106809
  function readdir12(dir2, strict) {
106465
- return new Promise((resolve41, reject2) => {
106810
+ return new Promise((resolve43, reject2) => {
106466
106811
  fs3.readdir(dir2, { withFileTypes: true }, (err, files) => {
106467
106812
  if (err) {
106468
106813
  switch (err.code) {
@@ -106470,7 +106815,7 @@ var require_readdir_glob = __commonJS({
106470
106815
  if (strict) {
106471
106816
  reject2(err);
106472
106817
  } else {
106473
- resolve41([]);
106818
+ resolve43([]);
106474
106819
  }
106475
106820
  break;
106476
106821
  case "ENOTSUP":
@@ -106480,7 +106825,7 @@ var require_readdir_glob = __commonJS({
106480
106825
  case "ENAMETOOLONG":
106481
106826
  // Filename too long
106482
106827
  case "UNKNOWN":
106483
- resolve41([]);
106828
+ resolve43([]);
106484
106829
  break;
106485
106830
  case "ELOOP":
106486
106831
  // Too many levels of symbolic links
@@ -106489,30 +106834,30 @@ var require_readdir_glob = __commonJS({
106489
106834
  break;
106490
106835
  }
106491
106836
  } else {
106492
- resolve41(files);
106837
+ resolve43(files);
106493
106838
  }
106494
106839
  });
106495
106840
  });
106496
106841
  }
106497
106842
  function stat12(file, followSymlinks) {
106498
- return new Promise((resolve41, reject2) => {
106843
+ return new Promise((resolve43, reject2) => {
106499
106844
  const statFunc = followSymlinks ? fs3.stat : fs3.lstat;
106500
106845
  statFunc(file, (err, stats) => {
106501
106846
  if (err) {
106502
106847
  switch (err.code) {
106503
106848
  case "ENOENT":
106504
106849
  if (followSymlinks) {
106505
- resolve41(stat12(file, false));
106850
+ resolve43(stat12(file, false));
106506
106851
  } else {
106507
- resolve41(null);
106852
+ resolve43(null);
106508
106853
  }
106509
106854
  break;
106510
106855
  default:
106511
- resolve41(null);
106856
+ resolve43(null);
106512
106857
  break;
106513
106858
  }
106514
106859
  } else {
106515
- resolve41(stats);
106860
+ resolve43(stats);
106516
106861
  }
106517
106862
  });
106518
106863
  });
@@ -106602,7 +106947,7 @@ var require_readdir_glob = __commonJS({
106602
106947
  (skip) => new Minimatch(skip, { dot: true })
106603
106948
  );
106604
106949
  }
106605
- this.iterator = explore(resolve40(cwd || "."), this.options.follow, this.options.stat, this._shouldSkipDirectory.bind(this));
106950
+ this.iterator = explore(resolve42(cwd || "."), this.options.follow, this.options.stat, this._shouldSkipDirectory.bind(this));
106606
106951
  this.paused = false;
106607
106952
  this.inactive = false;
106608
106953
  this.aborted = false;
@@ -106856,10 +107201,10 @@ function awaitify(asyncFn, arity) {
106856
107201
  if (typeof args[arity - 1] === "function") {
106857
107202
  return asyncFn.apply(this, args);
106858
107203
  }
106859
- return new Promise((resolve40, reject2) => {
107204
+ return new Promise((resolve42, reject2) => {
106860
107205
  args[arity - 1] = (err, ...cbArgs) => {
106861
107206
  if (err) return reject2(err);
106862
- resolve40(cbArgs.length > 1 ? cbArgs : cbArgs[0]);
107207
+ resolve42(cbArgs.length > 1 ? cbArgs : cbArgs[0]);
106863
107208
  };
106864
107209
  asyncFn.apply(this, args);
106865
107210
  });
@@ -107041,13 +107386,13 @@ function mapSeries(coll, iteratee, callback) {
107041
107386
  return _asyncMap(eachOfSeries$1, coll, iteratee, callback);
107042
107387
  }
107043
107388
  function promiseCallback() {
107044
- let resolve40, reject2;
107389
+ let resolve42, reject2;
107045
107390
  function callback(err, ...args) {
107046
107391
  if (err) return reject2(err);
107047
- resolve40(args.length > 1 ? args : args[0]);
107392
+ resolve42(args.length > 1 ? args : args[0]);
107048
107393
  }
107049
107394
  callback[PROMISE_SYMBOL] = new Promise((res, rej) => {
107050
- resolve40 = res, reject2 = rej;
107395
+ resolve42 = res, reject2 = rej;
107051
107396
  });
107052
107397
  return callback;
107053
107398
  }
@@ -107320,8 +107665,8 @@ function queue$1(worker, concurrency, payload) {
107320
107665
  });
107321
107666
  }
107322
107667
  if (rejectOnError || !callback) {
107323
- return new Promise((resolve40, reject2) => {
107324
- res = resolve40;
107668
+ return new Promise((resolve42, reject2) => {
107669
+ res = resolve42;
107325
107670
  rej = reject2;
107326
107671
  });
107327
107672
  }
@@ -107360,10 +107705,10 @@ function queue$1(worker, concurrency, payload) {
107360
107705
  }
107361
107706
  const eventMethod = (name) => (handler) => {
107362
107707
  if (!handler) {
107363
- return new Promise((resolve40, reject2) => {
107708
+ return new Promise((resolve42, reject2) => {
107364
107709
  once3(name, (err, data) => {
107365
107710
  if (err) return reject2(err);
107366
- resolve40(data);
107711
+ resolve42(data);
107367
107712
  });
107368
107713
  });
107369
107714
  }
@@ -108539,7 +108884,7 @@ var require_polyfills = __commonJS({
108539
108884
  var constants2 = __require("constants");
108540
108885
  var origCwd = process.cwd;
108541
108886
  var cwd = null;
108542
- var platform3 = process.env.GRACEFUL_FS_PLATFORM || process.platform;
108887
+ var platform4 = process.env.GRACEFUL_FS_PLATFORM || process.platform;
108543
108888
  process.cwd = function() {
108544
108889
  if (!cwd)
108545
108890
  cwd = origCwd.call(process);
@@ -108598,7 +108943,7 @@ var require_polyfills = __commonJS({
108598
108943
  fs3.lchownSync = function() {
108599
108944
  };
108600
108945
  }
108601
- if (platform3 === "win32") {
108946
+ if (platform4 === "win32") {
108602
108947
  fs3.rename = typeof fs3.rename !== "function" ? fs3.rename : (function(fs$rename) {
108603
108948
  function rename6(from, to, cb) {
108604
108949
  var start = Date.now();
@@ -113369,25 +113714,25 @@ var require_util2 = __commonJS({
113369
113714
  };
113370
113715
  },
113371
113716
  createDeferredPromise: function() {
113372
- let resolve40;
113717
+ let resolve42;
113373
113718
  let reject2;
113374
113719
  const promise = new Promise((res, rej) => {
113375
- resolve40 = res;
113720
+ resolve42 = res;
113376
113721
  reject2 = rej;
113377
113722
  });
113378
113723
  return {
113379
113724
  promise,
113380
- resolve: resolve40,
113725
+ resolve: resolve42,
113381
113726
  reject: reject2
113382
113727
  };
113383
113728
  },
113384
113729
  promisify(fn) {
113385
- return new Promise((resolve40, reject2) => {
113730
+ return new Promise((resolve42, reject2) => {
113386
113731
  fn((err, ...args) => {
113387
113732
  if (err) {
113388
113733
  return reject2(err);
113389
113734
  }
113390
- return resolve40(...args);
113735
+ return resolve42(...args);
113391
113736
  });
113392
113737
  });
113393
113738
  },
@@ -114179,7 +114524,7 @@ var require_end_of_stream2 = __commonJS({
114179
114524
  validateBoolean3(opts.cleanup, "cleanup");
114180
114525
  autoCleanup = opts.cleanup;
114181
114526
  }
114182
- return new Promise2((resolve40, reject2) => {
114527
+ return new Promise2((resolve42, reject2) => {
114183
114528
  const cleanup = eos(stream, opts, (err) => {
114184
114529
  if (autoCleanup) {
114185
114530
  cleanup();
@@ -114187,7 +114532,7 @@ var require_end_of_stream2 = __commonJS({
114187
114532
  if (err) {
114188
114533
  reject2(err);
114189
114534
  } else {
114190
- resolve40();
114535
+ resolve42();
114191
114536
  }
114192
114537
  });
114193
114538
  });
@@ -115354,7 +115699,7 @@ var require_readable2 = __commonJS({
115354
115699
  error = this.readableEnded ? null : new AbortError();
115355
115700
  this.destroy(error);
115356
115701
  }
115357
- return new Promise2((resolve40, reject2) => eos(this, (err) => err && err !== error ? reject2(err) : resolve40(null)));
115702
+ return new Promise2((resolve42, reject2) => eos(this, (err) => err && err !== error ? reject2(err) : resolve42(null)));
115358
115703
  };
115359
115704
  Readable2.prototype.push = function(chunk, encoding) {
115360
115705
  return readableAddChunk(this, chunk, encoding, false);
@@ -115898,12 +116243,12 @@ var require_readable2 = __commonJS({
115898
116243
  }
115899
116244
  async function* createAsyncIterator(stream, options) {
115900
116245
  let callback = nop;
115901
- function next(resolve40) {
116246
+ function next(resolve42) {
115902
116247
  if (this === stream) {
115903
116248
  callback();
115904
116249
  callback = nop;
115905
116250
  } else {
115906
- callback = resolve40;
116251
+ callback = resolve42;
115907
116252
  }
115908
116253
  }
115909
116254
  stream.on("readable", next);
@@ -116956,7 +117301,7 @@ var require_duplexify = __commonJS({
116956
117301
  );
116957
117302
  };
116958
117303
  function fromAsyncGen(fn) {
116959
- let { promise, resolve: resolve40 } = createDeferredPromise();
117304
+ let { promise, resolve: resolve42 } = createDeferredPromise();
116960
117305
  const ac = new AbortController2();
116961
117306
  const signal = ac.signal;
116962
117307
  const value = fn(
@@ -116971,7 +117316,7 @@ var require_duplexify = __commonJS({
116971
117316
  throw new AbortError(void 0, {
116972
117317
  cause: signal.reason
116973
117318
  });
116974
- ({ promise, resolve: resolve40 } = createDeferredPromise());
117319
+ ({ promise, resolve: resolve42 } = createDeferredPromise());
116975
117320
  yield chunk;
116976
117321
  }
116977
117322
  })(),
@@ -116982,8 +117327,8 @@ var require_duplexify = __commonJS({
116982
117327
  return {
116983
117328
  value,
116984
117329
  write(chunk, encoding, cb) {
116985
- const _resolve = resolve40;
116986
- resolve40 = null;
117330
+ const _resolve = resolve42;
117331
+ resolve42 = null;
116987
117332
  _resolve({
116988
117333
  chunk,
116989
117334
  done: false,
@@ -116991,8 +117336,8 @@ var require_duplexify = __commonJS({
116991
117336
  });
116992
117337
  },
116993
117338
  final(cb) {
116994
- const _resolve = resolve40;
116995
- resolve40 = null;
117339
+ const _resolve = resolve42;
117340
+ resolve42 = null;
116996
117341
  _resolve({
116997
117342
  done: true,
116998
117343
  cb
@@ -117444,7 +117789,7 @@ var require_pipeline = __commonJS({
117444
117789
  callback();
117445
117790
  }
117446
117791
  };
117447
- const wait = () => new Promise2((resolve40, reject2) => {
117792
+ const wait = () => new Promise2((resolve42, reject2) => {
117448
117793
  if (error) {
117449
117794
  reject2(error);
117450
117795
  } else {
@@ -117452,7 +117797,7 @@ var require_pipeline = __commonJS({
117452
117797
  if (error) {
117453
117798
  reject2(error);
117454
117799
  } else {
117455
- resolve40();
117800
+ resolve42();
117456
117801
  }
117457
117802
  };
117458
117803
  }
@@ -118096,8 +118441,8 @@ var require_operators = __commonJS({
118096
118441
  next = null;
118097
118442
  }
118098
118443
  if (!done && (queue2.length >= highWaterMark2 || cnt >= concurrency)) {
118099
- await new Promise2((resolve40) => {
118100
- resume = resolve40;
118444
+ await new Promise2((resolve42) => {
118445
+ resume = resolve42;
118101
118446
  });
118102
118447
  }
118103
118448
  }
@@ -118131,8 +118476,8 @@ var require_operators = __commonJS({
118131
118476
  queue2.shift();
118132
118477
  maybeResume();
118133
118478
  }
118134
- await new Promise2((resolve40) => {
118135
- next = resolve40;
118479
+ await new Promise2((resolve42) => {
118480
+ next = resolve42;
118136
118481
  });
118137
118482
  }
118138
118483
  } finally {
@@ -118390,7 +118735,7 @@ var require_promises = __commonJS({
118390
118735
  var { finished } = require_end_of_stream2();
118391
118736
  require_stream2();
118392
118737
  function pipeline(...streams) {
118393
- return new Promise2((resolve40, reject2) => {
118738
+ return new Promise2((resolve42, reject2) => {
118394
118739
  let signal;
118395
118740
  let end;
118396
118741
  const lastArg = streams[streams.length - 1];
@@ -118405,7 +118750,7 @@ var require_promises = __commonJS({
118405
118750
  if (err) {
118406
118751
  reject2(err);
118407
118752
  } else {
118408
- resolve40(value);
118753
+ resolve42(value);
118409
118754
  }
118410
118755
  },
118411
118756
  {
@@ -123178,10 +123523,10 @@ var require_commonjs3 = __commonJS({
123178
123523
  * Return a void Promise that resolves once the stream ends.
123179
123524
  */
123180
123525
  async promise() {
123181
- return new Promise((resolve40, reject2) => {
123526
+ return new Promise((resolve42, reject2) => {
123182
123527
  this.on(DESTROYED, () => reject2(new Error("stream destroyed")));
123183
123528
  this.on("error", (er) => reject2(er));
123184
- this.on("end", () => resolve40());
123529
+ this.on("end", () => resolve42());
123185
123530
  });
123186
123531
  }
123187
123532
  /**
@@ -123205,7 +123550,7 @@ var require_commonjs3 = __commonJS({
123205
123550
  return Promise.resolve({ done: false, value: res });
123206
123551
  if (this[EOF])
123207
123552
  return stop();
123208
- let resolve40;
123553
+ let resolve42;
123209
123554
  let reject2;
123210
123555
  const onerr = (er) => {
123211
123556
  this.off("data", ondata);
@@ -123219,19 +123564,19 @@ var require_commonjs3 = __commonJS({
123219
123564
  this.off("end", onend);
123220
123565
  this.off(DESTROYED, ondestroy);
123221
123566
  this.pause();
123222
- resolve40({ value, done: !!this[EOF] });
123567
+ resolve42({ value, done: !!this[EOF] });
123223
123568
  };
123224
123569
  const onend = () => {
123225
123570
  this.off("error", onerr);
123226
123571
  this.off("data", ondata);
123227
123572
  this.off(DESTROYED, ondestroy);
123228
123573
  stop();
123229
- resolve40({ done: true, value: void 0 });
123574
+ resolve42({ done: true, value: void 0 });
123230
123575
  };
123231
123576
  const ondestroy = () => onerr(new Error("stream destroyed"));
123232
123577
  return new Promise((res2, rej) => {
123233
123578
  reject2 = rej;
123234
- resolve40 = res2;
123579
+ resolve42 = res2;
123235
123580
  this.once(DESTROYED, ondestroy);
123236
123581
  this.once("error", onerr);
123237
123582
  this.once("end", onend);
@@ -124247,9 +124592,9 @@ var require_commonjs4 = __commonJS({
124247
124592
  if (this.#asyncReaddirInFlight) {
124248
124593
  await this.#asyncReaddirInFlight;
124249
124594
  } else {
124250
- let resolve40 = () => {
124595
+ let resolve42 = () => {
124251
124596
  };
124252
- this.#asyncReaddirInFlight = new Promise((res) => resolve40 = res);
124597
+ this.#asyncReaddirInFlight = new Promise((res) => resolve42 = res);
124253
124598
  try {
124254
124599
  for (const e of await this.#fs.promises.readdir(fullpath, {
124255
124600
  withFileTypes: true
@@ -124262,7 +124607,7 @@ var require_commonjs4 = __commonJS({
124262
124607
  children.provisional = 0;
124263
124608
  }
124264
124609
  this.#asyncReaddirInFlight = void 0;
124265
- resolve40();
124610
+ resolve42();
124266
124611
  }
124267
124612
  return children.slice(0, children.provisional);
124268
124613
  }
@@ -125129,7 +125474,7 @@ var require_pattern = __commonJS({
125129
125474
  #isUNC;
125130
125475
  #isAbsolute;
125131
125476
  #followGlobstar = true;
125132
- constructor(patternList, globList, index2, platform3) {
125477
+ constructor(patternList, globList, index2, platform4) {
125133
125478
  if (!isPatternList(patternList)) {
125134
125479
  throw new TypeError("empty pattern list");
125135
125480
  }
@@ -125146,7 +125491,7 @@ var require_pattern = __commonJS({
125146
125491
  this.#patternList = patternList;
125147
125492
  this.#globList = globList;
125148
125493
  this.#index = index2;
125149
- this.#platform = platform3;
125494
+ this.#platform = platform4;
125150
125495
  if (this.#index === 0) {
125151
125496
  if (this.isUNC()) {
125152
125497
  const [p0, p1, p2, p3, ...prest] = this.#patternList;
@@ -125298,12 +125643,12 @@ var require_ignore = __commonJS({
125298
125643
  absoluteChildren;
125299
125644
  platform;
125300
125645
  mmopts;
125301
- constructor(ignored, { nobrace, nocase, noext, noglobstar, platform: platform3 = defaultPlatform }) {
125646
+ constructor(ignored, { nobrace, nocase, noext, noglobstar, platform: platform4 = defaultPlatform }) {
125302
125647
  this.relative = [];
125303
125648
  this.absolute = [];
125304
125649
  this.relativeChildren = [];
125305
125650
  this.absoluteChildren = [];
125306
- this.platform = platform3;
125651
+ this.platform = platform4;
125307
125652
  this.mmopts = {
125308
125653
  dot: true,
125309
125654
  nobrace,
@@ -125311,7 +125656,7 @@ var require_ignore = __commonJS({
125311
125656
  noext,
125312
125657
  noglobstar,
125313
125658
  optimizationLevel: 2,
125314
- platform: platform3,
125659
+ platform: platform4,
125315
125660
  nocomment: true,
125316
125661
  nonegate: true
125317
125662
  };
@@ -127035,11 +127380,11 @@ var require_core = __commonJS({
127035
127380
  this._finalize();
127036
127381
  }
127037
127382
  var self2 = this;
127038
- return new Promise(function(resolve40, reject2) {
127383
+ return new Promise(function(resolve42, reject2) {
127039
127384
  var errored;
127040
127385
  self2._module.on("end", function() {
127041
127386
  if (!errored) {
127042
- resolve40();
127387
+ resolve42();
127043
127388
  }
127044
127389
  });
127045
127390
  self2._module.on("error", function(err) {
@@ -127533,8 +127878,8 @@ var require_zip_archive_entry = __commonJS({
127533
127878
  }
127534
127879
  this.name = name;
127535
127880
  };
127536
- ZipArchiveEntry.prototype.setPlatform = function(platform3) {
127537
- this.platform = platform3;
127881
+ ZipArchiveEntry.prototype.setPlatform = function(platform4) {
127882
+ this.platform = platform4;
127538
127883
  };
127539
127884
  ZipArchiveEntry.prototype.setSize = function(size) {
127540
127885
  if (size < 0) {
@@ -129479,8 +129824,8 @@ var require_streamx = __commonJS({
129479
129824
  return this;
129480
129825
  },
129481
129826
  next() {
129482
- return new Promise(function(resolve40, reject2) {
129483
- promiseResolve = resolve40;
129827
+ return new Promise(function(resolve42, reject2) {
129828
+ promiseResolve = resolve42;
129484
129829
  promiseReject = reject2;
129485
129830
  const data = stream.read();
129486
129831
  if (data !== null) ondata(data);
@@ -129510,11 +129855,11 @@ var require_streamx = __commonJS({
129510
129855
  }
129511
129856
  function destroy(err) {
129512
129857
  stream.destroy(err);
129513
- return new Promise((resolve40, reject2) => {
129514
- if (stream._duplexState & DESTROYED) return resolve40({ value: void 0, done: true });
129858
+ return new Promise((resolve42, reject2) => {
129859
+ if (stream._duplexState & DESTROYED) return resolve42({ value: void 0, done: true });
129515
129860
  stream.once("close", function() {
129516
129861
  if (err) reject2(err);
129517
- else resolve40({ value: void 0, done: true });
129862
+ else resolve42({ value: void 0, done: true });
129518
129863
  });
129519
129864
  });
129520
129865
  }
@@ -129558,8 +129903,8 @@ var require_streamx = __commonJS({
129558
129903
  const writes = pending + (ws._duplexState & WRITE_WRITING ? 1 : 0);
129559
129904
  if (writes === 0) return Promise.resolve(true);
129560
129905
  if (state.drains === null) state.drains = [];
129561
- return new Promise((resolve40) => {
129562
- state.drains.push({ writes, resolve: resolve40 });
129906
+ return new Promise((resolve42) => {
129907
+ state.drains.push({ writes, resolve: resolve42 });
129563
129908
  });
129564
129909
  }
129565
129910
  write(data) {
@@ -129664,10 +130009,10 @@ var require_streamx = __commonJS({
129664
130009
  cb(null);
129665
130010
  }
129666
130011
  function pipelinePromise(...streams) {
129667
- return new Promise((resolve40, reject2) => {
130012
+ return new Promise((resolve42, reject2) => {
129668
130013
  return pipeline(...streams, (err) => {
129669
130014
  if (err) return reject2(err);
129670
- resolve40();
130015
+ resolve42();
129671
130016
  });
129672
130017
  });
129673
130018
  }
@@ -130324,16 +130669,16 @@ var require_extract = __commonJS({
130324
130669
  entryCallback = null;
130325
130670
  cb(err);
130326
130671
  }
130327
- function onnext(resolve40, reject2) {
130672
+ function onnext(resolve42, reject2) {
130328
130673
  if (error) {
130329
130674
  return reject2(error);
130330
130675
  }
130331
130676
  if (entryStream) {
130332
- resolve40({ value: entryStream, done: false });
130677
+ resolve42({ value: entryStream, done: false });
130333
130678
  entryStream = null;
130334
130679
  return;
130335
130680
  }
130336
- promiseResolve = resolve40;
130681
+ promiseResolve = resolve42;
130337
130682
  promiseReject = reject2;
130338
130683
  consumeCallback(null);
130339
130684
  if (extract._finished && promiseResolve) {
@@ -130361,11 +130706,11 @@ var require_extract = __commonJS({
130361
130706
  function destroy(err) {
130362
130707
  extract.destroy(err);
130363
130708
  consumeCallback(err);
130364
- return new Promise((resolve40, reject2) => {
130365
- if (extract.destroyed) return resolve40({ value: void 0, done: true });
130709
+ return new Promise((resolve42, reject2) => {
130710
+ if (extract.destroyed) return resolve42({ value: void 0, done: true });
130366
130711
  extract.once("close", function() {
130367
130712
  if (err) reject2(err);
130368
- else resolve40({ value: void 0, done: true });
130713
+ else resolve42({ value: void 0, done: true });
130369
130714
  });
130370
130715
  });
130371
130716
  }
@@ -133702,6 +134047,20 @@ var init_register_settings_sync_inbound_routes = __esm({
133702
134047
  });
133703
134048
 
133704
134049
  // ../dashboard/src/routes/register-agent-core-routes.ts
134050
+ function isCompatibleDefaultHeartbeatPath(path5, agent) {
134051
+ const trimmed = path5?.trim();
134052
+ if (!trimmed) {
134053
+ return false;
134054
+ }
134055
+ if (trimmed === getDefaultHeartbeatProcedurePath(agent.id, agent.name)) {
134056
+ return true;
134057
+ }
134058
+ if (trimmed === getDefaultHeartbeatProcedurePath(agent.id)) {
134059
+ return true;
134060
+ }
134061
+ const safeId = agent.id.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
134062
+ return new RegExp(`^\\.fusion/agents/[^/]+-${safeId}/HEARTBEAT\\.md$`).test(trimmed);
134063
+ }
133705
134064
  function registerAgentCoreListCreateRoutes(ctx, deps) {
133706
134065
  const { router, getProjectContext: getProjectContext3, rethrowAsApiError: rethrowAsApiError8 } = ctx;
133707
134066
  const { sanitizeAgentTaskLinks, validateAgentInstructionsPayload } = deps;
@@ -133831,7 +134190,7 @@ function registerAgentCoreListCreateRoutes(ctx, deps) {
133831
134190
  bundleConfig: bundleConfig ?? void 0,
133832
134191
  heartbeatProcedurePath: heartbeatProcedurePath ?? void 0
133833
134192
  });
133834
- const expectedDefaultPath = getDefaultHeartbeatProcedurePath(agent.id);
134193
+ const expectedDefaultPath = getDefaultHeartbeatProcedurePath(agent.id, agent.name);
133835
134194
  if (agent.heartbeatProcedurePath === expectedDefaultPath) {
133836
134195
  try {
133837
134196
  await ensureDefaultHeartbeatProcedureFile(scopedStore.getRootDir(), expectedDefaultPath, HEARTBEAT_PROCEDURE);
@@ -134089,7 +134448,7 @@ function registerAgentCoreRoutes(ctx, deps) {
134089
134448
  if (!existing) {
134090
134449
  throw notFound(`agent ${req.params.id} not found`);
134091
134450
  }
134092
- const targetPath = getDefaultHeartbeatProcedurePath(req.params.id);
134451
+ const targetPath = isCompatibleDefaultHeartbeatPath(existing.heartbeatProcedurePath, existing) ? existing.heartbeatProcedurePath : getDefaultHeartbeatProcedurePath(existing.id, existing.name);
134093
134452
  const filePath = await ensureDefaultHeartbeatProcedureFile(
134094
134453
  scopedStore.getRootDir(),
134095
134454
  targetPath,
@@ -137349,9 +137708,9 @@ function registerProxyRoutes(router, deps) {
137349
137708
  if (req.rawBody && req.rawBody.length > 0) {
137350
137709
  body = req.rawBody;
137351
137710
  } else {
137352
- await new Promise((resolve40, reject2) => {
137711
+ await new Promise((resolve42, reject2) => {
137353
137712
  req.on("data", (chunk) => chunks.push(chunk));
137354
- req.on("end", resolve40);
137713
+ req.on("end", resolve42);
137355
137714
  req.on("error", reject2);
137356
137715
  });
137357
137716
  if (chunks.length > 0) {
@@ -137482,6 +137841,7 @@ var init_register_model_routes = __esm({
137482
137841
  let defaultProvider;
137483
137842
  let defaultModelId;
137484
137843
  let useClaudeCli = false;
137844
+ let useDroidCli = false;
137485
137845
  if (store) {
137486
137846
  try {
137487
137847
  const globalStore = store.getGlobalSettingsStore();
@@ -137491,6 +137851,7 @@ var init_register_model_routes = __esm({
137491
137851
  defaultProvider = globalSettings.defaultProvider;
137492
137852
  defaultModelId = globalSettings.defaultModelId;
137493
137853
  useClaudeCli = globalSettings.useClaudeCli === true;
137854
+ useDroidCli = globalSettings.useDroidCli === true;
137494
137855
  } catch {
137495
137856
  }
137496
137857
  }
@@ -137516,6 +137877,9 @@ var init_register_model_routes = __esm({
137516
137877
  if (!useClaudeCli) {
137517
137878
  models = models.filter((m) => m.provider !== "pi-claude-cli");
137518
137879
  }
137880
+ if (!useDroidCli) {
137881
+ models = models.filter((m) => m.provider !== "droid-cli");
137882
+ }
137519
137883
  res.json({
137520
137884
  models,
137521
137885
  favoriteProviders,
@@ -137763,13 +138127,13 @@ function getHomeDir5() {
137763
138127
  return process.env.HOME || process.env.USERPROFILE || os4.homedir();
137764
138128
  }
137765
138129
  function execFileAsync5(file, args, options) {
137766
- return new Promise((resolve40, reject2) => {
138130
+ return new Promise((resolve42, reject2) => {
137767
138131
  child_process.execFile(file, args, options, (error, stdout, stderr) => {
137768
138132
  if (error) {
137769
138133
  reject2(error);
137770
138134
  return;
137771
138135
  }
137772
- resolve40({ stdout: String(stdout), stderr: String(stderr) });
138136
+ resolve42({ stdout: String(stdout), stderr: String(stderr) });
137773
138137
  });
137774
138138
  });
137775
138139
  }
@@ -137828,7 +138192,7 @@ function formatDuration(ms) {
137828
138192
  return remHours > 0 ? `${days}d ${remHours}h` : `${days}d`;
137829
138193
  }
137830
138194
  function httpsRequest(url, options) {
137831
- return new Promise((resolve40, reject2) => {
138195
+ return new Promise((resolve42, reject2) => {
137832
138196
  const parsed = new URL(url);
137833
138197
  const req = https.request(
137834
138198
  {
@@ -137848,7 +138212,7 @@ function httpsRequest(url, options) {
137848
138212
  if (typeof v === "string") hdrs[k.toLowerCase()] = v;
137849
138213
  else if (Array.isArray(v)) hdrs[k.toLowerCase()] = v.join(", ");
137850
138214
  }
137851
- resolve40({
138215
+ resolve42({
137852
138216
  status: res.statusCode || 0,
137853
138217
  headers: hdrs,
137854
138218
  body: Buffer.concat(chunks).toString("utf-8")
@@ -138095,7 +138459,7 @@ async function fetchClaudeUsageViaCli() {
138095
138459
  env: { ...process.env, TERM: "xterm-256color" }
138096
138460
  };
138097
138461
  if (isWindows) ptyOptions.useConpty = false;
138098
- const output = await new Promise((resolve40, reject2) => {
138462
+ const output = await new Promise((resolve42, reject2) => {
138099
138463
  let buf = "";
138100
138464
  let settled = false;
138101
138465
  let sentCommand = false;
@@ -138111,7 +138475,7 @@ async function fetchClaudeUsageViaCli() {
138111
138475
  }
138112
138476
  const clean = _stripClaudeAnsi(buf);
138113
138477
  if (clean.includes("Current session") || clean.includes("% left") || clean.includes("% used")) {
138114
- resolve40(buf);
138478
+ resolve42(buf);
138115
138479
  } else {
138116
138480
  reject2(new Error("Claude CLI timed out after 60s \u2014 got output but no usage data. Try running `claude /usage` manually."));
138117
138481
  }
@@ -138162,7 +138526,7 @@ async function fetchClaudeUsageViaCli() {
138162
138526
  ptyProcess.kill();
138163
138527
  } catch {
138164
138528
  }
138165
- resolve40(buf);
138529
+ resolve42(buf);
138166
138530
  }
138167
138531
  }, 2e3);
138168
138532
  }
@@ -138173,7 +138537,7 @@ async function fetchClaudeUsageViaCli() {
138173
138537
  if (settled) return;
138174
138538
  settled = true;
138175
138539
  clearTimeout(timeout2);
138176
- resolve40(buf);
138540
+ resolve42(buf);
138177
138541
  });
138178
138542
  });
138179
138543
  const cleanOutput = _stripClaudeAnsi(output);
@@ -138841,9 +139205,9 @@ async function fetchGitHubCopilotUsage() {
138841
139205
  return usage;
138842
139206
  }
138843
139207
  function withTimeout(providerPromise, providerName, timeoutMs = PROVIDER_FETCH_TIMEOUT_MS) {
138844
- return new Promise((resolve40) => {
139208
+ return new Promise((resolve42) => {
138845
139209
  const timer = setTimeout(() => {
138846
- resolve40({
139210
+ resolve42({
138847
139211
  name: providerName,
138848
139212
  icon: "\u23F1\uFE0F",
138849
139213
  status: "error",
@@ -138853,10 +139217,10 @@ function withTimeout(providerPromise, providerName, timeoutMs = PROVIDER_FETCH_T
138853
139217
  }, timeoutMs);
138854
139218
  providerPromise.then((result) => {
138855
139219
  clearTimeout(timer);
138856
- resolve40(result);
139220
+ resolve42(result);
138857
139221
  }).catch((err) => {
138858
139222
  clearTimeout(timer);
138859
- resolve40({
139223
+ resolve42({
138860
139224
  name: providerName,
138861
139225
  icon: "\u23F1\uFE0F",
138862
139226
  status: "error",
@@ -138911,7 +139275,7 @@ var init_usage = __esm({
138911
139275
  ANTHROPIC_OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
138912
139276
  ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
138913
139277
  CLAUDE_USAGE_USER_AGENT = "claude-code-fusion-dashboard";
138914
- _sleep = (ms) => new Promise((resolve40) => setTimeout(resolve40, ms));
139278
+ _sleep = (ms) => new Promise((resolve42) => setTimeout(resolve42, ms));
138915
139279
  sleepFn = _sleep;
138916
139280
  PROVIDER_FETCH_TIMEOUT_MS = 1e4;
138917
139281
  CLAUDE_FETCH_TIMEOUT_MS = 75e3;
@@ -138943,7 +139307,7 @@ var init_register_usage_routes = __esm({
138943
139307
  });
138944
139308
 
138945
139309
  // ../dashboard/src/claude-cli-probe.ts
138946
- import { spawn as spawn10 } from "node:child_process";
139310
+ import { spawn as spawn11 } from "node:child_process";
138947
139311
  async function probeClaudeCli(options = {}) {
138948
139312
  const startedAt = Date.now();
138949
139313
  const timeoutMs = options.timeoutMs ?? PROBE_TIMEOUT_MS;
@@ -138953,7 +139317,7 @@ async function probeClaudeCli(options = {}) {
138953
139317
  resolvePromise({ ...result, probeDurationMs: Date.now() - startedAt });
138954
139318
  };
138955
139319
  let settled = false;
138956
- const child = spawn10(binaryPath ?? "claude", ["--version"], {
139320
+ const child = spawn11(binaryPath ?? "claude", ["--version"], {
138957
139321
  stdio: ["ignore", "pipe", "pipe"]
138958
139322
  });
138959
139323
  const timer = setTimeout(() => {
@@ -139011,7 +139375,7 @@ async function probeClaudeCli(options = {}) {
139011
139375
  async function tryResolveBinaryPath3(binary) {
139012
139376
  return new Promise((resolvePromise) => {
139013
139377
  const which = process.platform === "win32" ? "where" : "which";
139014
- const child = spawn10(which, [binary], { stdio: ["ignore", "pipe", "ignore"] });
139378
+ const child = spawn11(which, [binary], { stdio: ["ignore", "pipe", "ignore"] });
139015
139379
  let out = "";
139016
139380
  child.stdout?.on("data", (chunk) => {
139017
139381
  out += chunk.toString("utf-8");
@@ -139036,7 +139400,7 @@ var init_claude_cli_probe = __esm({
139036
139400
  });
139037
139401
 
139038
139402
  // ../dashboard/src/droid-cli-probe.ts
139039
- import { spawn as spawn11 } from "node:child_process";
139403
+ import { spawn as spawn12 } from "node:child_process";
139040
139404
  async function probeDroidCli(options = {}) {
139041
139405
  const startedAt = Date.now();
139042
139406
  const timeoutMs = options.timeoutMs ?? PROBE_TIMEOUT_MS2;
@@ -139046,7 +139410,7 @@ async function probeDroidCli(options = {}) {
139046
139410
  resolvePromise({ ...result, probeDurationMs: Date.now() - startedAt });
139047
139411
  };
139048
139412
  let settled = false;
139049
- const child = spawn11(binaryPath ?? "droid", ["--version"], {
139413
+ const child = spawn12(binaryPath ?? "droid", ["--version"], {
139050
139414
  stdio: ["ignore", "pipe", "pipe"]
139051
139415
  });
139052
139416
  const timer = setTimeout(() => {
@@ -139104,7 +139468,7 @@ async function probeDroidCli(options = {}) {
139104
139468
  async function tryResolveBinaryPath4(binary) {
139105
139469
  return new Promise((resolvePromise) => {
139106
139470
  const which = process.platform === "win32" ? "where" : "which";
139107
- const child = spawn11(which, [binary], { stdio: ["ignore", "pipe", "ignore"] });
139471
+ const child = spawn12(which, [binary], { stdio: ["ignore", "pipe", "ignore"] });
139108
139472
  let out = "";
139109
139473
  child.stdout?.on("data", (chunk) => {
139110
139474
  out += chunk.toString("utf-8");
@@ -139479,8 +139843,8 @@ var init_register_auth_routes = __esm({
139479
139843
  loginInProgress.set(provider, abortController);
139480
139844
  let authResolve;
139481
139845
  let authReject;
139482
- const authUrlPromise = new Promise((resolve40, reject2) => {
139483
- authResolve = resolve40;
139846
+ const authUrlPromise = new Promise((resolve42, reject2) => {
139847
+ authResolve = resolve42;
139484
139848
  authReject = reject2;
139485
139849
  });
139486
139850
  const loginPromise = storage.login(provider, {
@@ -139948,7 +140312,7 @@ function stripAnsi2(str) {
139948
140312
  return str.replace(/\x1B\[[0-9;]*[mGKJHFABCDSTsu]/g, "");
139949
140313
  }
139950
140314
  async function mintAgentApiKeyViaCli(opts) {
139951
- const { spawn: spawn17 } = await import("node:child_process");
140315
+ const { spawn: spawn19 } = await import("node:child_process");
139952
140316
  const bin = opts.cliBinaryPath ?? "paperclipai";
139953
140317
  const args = [
139954
140318
  "agent",
@@ -139969,10 +140333,10 @@ async function mintAgentApiKeyViaCli(opts) {
139969
140333
  args.push("--data-dir", opts.dataDir);
139970
140334
  }
139971
140335
  const timeoutMs = opts.cliTimeoutMs ?? 3e4;
139972
- return new Promise((resolve40, reject2) => {
140336
+ return new Promise((resolve42, reject2) => {
139973
140337
  let child;
139974
140338
  try {
139975
- child = spawn17(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
140339
+ child = spawn19(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
139976
140340
  } catch (err) {
139977
140341
  const code = err.code;
139978
140342
  if (code === "ENOENT") {
@@ -140043,7 +140407,7 @@ async function mintAgentApiKeyViaCli(opts) {
140043
140407
  const apiBase = (typeof r.apiBase === "string" ? r.apiBase : void 0) ?? (typeof r.api_base === "string" ? r.api_base : void 0);
140044
140408
  const agentId = (typeof r.agentId === "string" ? r.agentId : void 0) ?? (typeof r.id === "string" ? r.id : void 0);
140045
140409
  const companyId = typeof r.companyId === "string" ? r.companyId : void 0;
140046
- resolve40({ apiKey, apiBase, agentId, companyId, raw: parsed });
140410
+ resolve42({ apiKey, apiBase, agentId, companyId, raw: parsed });
140047
140411
  });
140048
140412
  });
140049
140413
  }
@@ -140055,7 +140419,7 @@ function remapSpawnError(err, bin) {
140055
140419
  return err instanceof Error ? err : new Error(String(err));
140056
140420
  }
140057
140421
  async function spawnPaperclipCliJson(args, opts) {
140058
- const { spawn: spawn17 } = await import("node:child_process");
140422
+ const { spawn: spawn19 } = await import("node:child_process");
140059
140423
  const bin = opts.cliBinaryPath ?? "paperclipai";
140060
140424
  const fullArgs = [...args, "--json"];
140061
140425
  if (opts.cliConfigPath) {
@@ -140063,10 +140427,10 @@ async function spawnPaperclipCliJson(args, opts) {
140063
140427
  }
140064
140428
  const timeoutMs = opts.cliTimeoutMs ?? 15e3;
140065
140429
  const label = ["paperclipai", ...args].join(" ");
140066
- return new Promise((resolve40, reject2) => {
140430
+ return new Promise((resolve42, reject2) => {
140067
140431
  let child;
140068
140432
  try {
140069
- child = spawn17(bin, fullArgs, { stdio: ["ignore", "pipe", "pipe"] });
140433
+ child = spawn19(bin, fullArgs, { stdio: ["ignore", "pipe", "pipe"] });
140070
140434
  } catch (err) {
140071
140435
  reject2(remapSpawnError(err, bin));
140072
140436
  return;
@@ -140109,7 +140473,7 @@ async function spawnPaperclipCliJson(args, opts) {
140109
140473
  return;
140110
140474
  }
140111
140475
  try {
140112
- resolve40(JSON.parse(cleaned));
140476
+ resolve42(JSON.parse(cleaned));
140113
140477
  } catch {
140114
140478
  reject2(new Error(`${label} returned non-JSON output: ${cleaned.slice(0, 200)}`));
140115
140479
  }
@@ -140238,7 +140602,7 @@ var init_paperclip_client = __esm({
140238
140602
  // ../../plugins/fusion-plugin-paperclip-runtime/dist/runtime-adapter.js
140239
140603
  import { randomUUID as randomUUID20 } from "node:crypto";
140240
140604
  function sleep4(ms) {
140241
- return new Promise((resolve40) => setTimeout(resolve40, ms));
140605
+ return new Promise((resolve42) => setTimeout(resolve42, ms));
140242
140606
  }
140243
140607
  function asString2(value) {
140244
140608
  return typeof value === "string" ? value : void 0;
@@ -140879,8 +141243,184 @@ var init_register_runtime_provider_routes = __esm({
140879
141243
  }
140880
141244
  });
140881
141245
 
141246
+ // ../dashboard/src/cli-package-version.ts
141247
+ import { existsSync as existsSync32, readFileSync as readFileSync10 } from "node:fs";
141248
+ import { dirname as dirname15, resolve as resolve23 } from "node:path";
141249
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
141250
+ function readCliPackageVersion(pkgPath) {
141251
+ if (!existsSync32(pkgPath)) {
141252
+ return null;
141253
+ }
141254
+ try {
141255
+ const parsed = JSON.parse(readFileSync10(pkgPath, "utf-8"));
141256
+ if (parsed.name === CLI_PACKAGE_NAME && typeof parsed.version === "string" && parsed.version.length > 0) {
141257
+ return {
141258
+ packageJsonPath: pkgPath,
141259
+ version: parsed.version
141260
+ };
141261
+ }
141262
+ } catch {
141263
+ }
141264
+ return null;
141265
+ }
141266
+ function resolveCliPackageVersionInfo(startDir) {
141267
+ let currentDir = startDir;
141268
+ for (let i = 0; i < 8; i += 1) {
141269
+ const versionInfo = readCliPackageVersion(resolve23(currentDir, "package.json"));
141270
+ if (versionInfo) {
141271
+ return versionInfo;
141272
+ }
141273
+ const parentDir = resolve23(currentDir, "..");
141274
+ if (parentDir === currentDir) {
141275
+ break;
141276
+ }
141277
+ currentDir = parentDir;
141278
+ }
141279
+ currentDir = startDir;
141280
+ for (let i = 0; i < 8; i += 1) {
141281
+ const versionInfo = readCliPackageVersion(resolve23(currentDir, "..", "cli", "package.json"));
141282
+ if (versionInfo) {
141283
+ return versionInfo;
141284
+ }
141285
+ const parentDir = resolve23(currentDir, "..");
141286
+ if (parentDir === currentDir) {
141287
+ break;
141288
+ }
141289
+ currentDir = parentDir;
141290
+ }
141291
+ return null;
141292
+ }
141293
+ function getCliPackageVersion(importMetaUrl = import.meta.url) {
141294
+ const startDir = dirname15(fileURLToPath4(importMetaUrl));
141295
+ return resolveCliPackageVersionInfo(startDir)?.version ?? process.env.npm_package_version ?? "0.0.0";
141296
+ }
141297
+ var CLI_PACKAGE_NAME;
141298
+ var init_cli_package_version = __esm({
141299
+ "../dashboard/src/cli-package-version.ts"() {
141300
+ "use strict";
141301
+ CLI_PACKAGE_NAME = "@runfusion/fusion";
141302
+ }
141303
+ });
141304
+
141305
+ // ../dashboard/src/routes/register-fn-binary-routes.ts
141306
+ import { spawn as spawn13 } from "node:child_process";
141307
+ function buildStatusPayload(binary, expectedVersion) {
141308
+ let state = "missing";
141309
+ if (binary.installed) {
141310
+ state = binary.version && binary.version !== expectedVersion ? "version-mismatch" : "installed";
141311
+ }
141312
+ return {
141313
+ binary,
141314
+ expectedVersion,
141315
+ state,
141316
+ install: {
141317
+ npm: FN_INSTALL_NPM,
141318
+ curl: FN_INSTALL_CURL,
141319
+ package: FN_NPM_PACKAGE
141320
+ }
141321
+ };
141322
+ }
141323
+ function runNpmInstall() {
141324
+ const startedAt = Date.now();
141325
+ const command = FN_INSTALL_NPM;
141326
+ return new Promise((resolve42) => {
141327
+ let stdout = "";
141328
+ let stderr = "";
141329
+ let timedOut = false;
141330
+ const child = spawn13("npm", ["install", "-g", FN_NPM_PACKAGE], {
141331
+ stdio: ["ignore", "pipe", "pipe"],
141332
+ shell: false
141333
+ });
141334
+ const timer = setTimeout(() => {
141335
+ timedOut = true;
141336
+ try {
141337
+ child.kill("SIGKILL");
141338
+ } catch {
141339
+ }
141340
+ }, INSTALL_TIMEOUT_MS);
141341
+ const append = (target, chunk) => {
141342
+ const text = chunk.toString("utf8");
141343
+ if (target === "stdout") {
141344
+ if (stdout.length < MAX_OUTPUT_BYTES2) {
141345
+ stdout += text.slice(0, MAX_OUTPUT_BYTES2 - stdout.length);
141346
+ }
141347
+ } else {
141348
+ if (stderr.length < MAX_OUTPUT_BYTES2) {
141349
+ stderr += text.slice(0, MAX_OUTPUT_BYTES2 - stderr.length);
141350
+ }
141351
+ }
141352
+ };
141353
+ child.stdout?.on("data", (c) => append("stdout", c));
141354
+ child.stderr?.on("data", (c) => append("stderr", c));
141355
+ child.on("error", (err) => {
141356
+ clearTimeout(timer);
141357
+ resolve42({
141358
+ success: false,
141359
+ exitCode: null,
141360
+ stdout,
141361
+ stderr: stderr || err.message,
141362
+ command,
141363
+ durationMs: Date.now() - startedAt
141364
+ });
141365
+ });
141366
+ child.on("close", (exitCode) => {
141367
+ clearTimeout(timer);
141368
+ const combined = `${stdout}
141369
+ ${stderr}`;
141370
+ const eaccesHit = /EACCES|permission denied|Operation not permitted/i.test(combined);
141371
+ const success = exitCode === 0 && !timedOut;
141372
+ resolve42({
141373
+ success,
141374
+ exitCode,
141375
+ stdout,
141376
+ stderr: timedOut ? `${stderr}
141377
+ [install timed out after ${INSTALL_TIMEOUT_MS / 1e3}s]` : stderr,
141378
+ command,
141379
+ durationMs: Date.now() - startedAt,
141380
+ permissionsHint: !success && eaccesHit ? "npm reported a permissions error. On macOS/Linux this usually means npm's global prefix needs `sudo` or a fix to your npm prefix (https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally)." : void 0
141381
+ });
141382
+ });
141383
+ });
141384
+ }
141385
+ var INSTALL_TIMEOUT_MS, MAX_OUTPUT_BYTES2, registerFnBinaryRoutes;
141386
+ var init_register_fn_binary_routes = __esm({
141387
+ "../dashboard/src/routes/register-fn-binary-routes.ts"() {
141388
+ "use strict";
141389
+ init_src();
141390
+ init_api_error();
141391
+ init_cli_package_version();
141392
+ INSTALL_TIMEOUT_MS = 18e4;
141393
+ MAX_OUTPUT_BYTES2 = 64 * 1024;
141394
+ registerFnBinaryRoutes = (ctx) => {
141395
+ const { router, rethrowAsApiError: rethrowAsApiError8 } = ctx;
141396
+ router.get("/system/fn-binary/status", async (_req, res) => {
141397
+ try {
141398
+ const binary = await detectFnBinary();
141399
+ const expectedVersion = getCliPackageVersion();
141400
+ res.json(buildStatusPayload(binary, expectedVersion));
141401
+ } catch (err) {
141402
+ if (err instanceof ApiError) throw err;
141403
+ rethrowAsApiError8(err);
141404
+ }
141405
+ });
141406
+ router.post("/system/fn-binary/install", async (_req, res) => {
141407
+ try {
141408
+ const installResult = await runNpmInstall();
141409
+ const binary = await detectFnBinary();
141410
+ const expectedVersion = getCliPackageVersion();
141411
+ const status = buildStatusPayload(binary, expectedVersion);
141412
+ res.json({ ...status, installResult });
141413
+ } catch (err) {
141414
+ if (err instanceof ApiError) throw err;
141415
+ rethrowAsApiError8(err);
141416
+ }
141417
+ });
141418
+ };
141419
+ }
141420
+ });
141421
+
140882
141422
  // ../dashboard/src/update-check.ts
140883
- import { readFileSync as readFileSync10 } from "node:fs";
141423
+ import { readFileSync as readFileSync11 } from "node:fs";
140884
141424
  import { mkdir as mkdir17, rm as rm5, writeFile as writeFile15 } from "node:fs/promises";
140885
141425
  import { join as join47 } from "node:path";
140886
141426
  function ttlForFrequency(frequency) {
@@ -140920,7 +141460,7 @@ function isValidResult(value) {
140920
141460
  }
140921
141461
  function readCachedUpdateCheck(fusionDir) {
140922
141462
  try {
140923
- const raw = readFileSync10(getCachePath(fusionDir), "utf-8");
141463
+ const raw = readFileSync11(getCachePath(fusionDir), "utf-8");
140924
141464
  const parsed = JSON.parse(raw);
140925
141465
  return isValidResult(parsed) ? parsed : null;
140926
141466
  } catch {
@@ -140987,65 +141527,6 @@ var init_update_check = __esm({
140987
141527
  }
140988
141528
  });
140989
141529
 
140990
- // ../dashboard/src/cli-package-version.ts
140991
- import { existsSync as existsSync32, readFileSync as readFileSync11 } from "node:fs";
140992
- import { dirname as dirname15, resolve as resolve23 } from "node:path";
140993
- import { fileURLToPath as fileURLToPath4 } from "node:url";
140994
- function readCliPackageVersion(pkgPath) {
140995
- if (!existsSync32(pkgPath)) {
140996
- return null;
140997
- }
140998
- try {
140999
- const parsed = JSON.parse(readFileSync11(pkgPath, "utf-8"));
141000
- if (parsed.name === CLI_PACKAGE_NAME && typeof parsed.version === "string" && parsed.version.length > 0) {
141001
- return {
141002
- packageJsonPath: pkgPath,
141003
- version: parsed.version
141004
- };
141005
- }
141006
- } catch {
141007
- }
141008
- return null;
141009
- }
141010
- function resolveCliPackageVersionInfo(startDir) {
141011
- let currentDir = startDir;
141012
- for (let i = 0; i < 8; i += 1) {
141013
- const versionInfo = readCliPackageVersion(resolve23(currentDir, "package.json"));
141014
- if (versionInfo) {
141015
- return versionInfo;
141016
- }
141017
- const parentDir = resolve23(currentDir, "..");
141018
- if (parentDir === currentDir) {
141019
- break;
141020
- }
141021
- currentDir = parentDir;
141022
- }
141023
- currentDir = startDir;
141024
- for (let i = 0; i < 8; i += 1) {
141025
- const versionInfo = readCliPackageVersion(resolve23(currentDir, "..", "cli", "package.json"));
141026
- if (versionInfo) {
141027
- return versionInfo;
141028
- }
141029
- const parentDir = resolve23(currentDir, "..");
141030
- if (parentDir === currentDir) {
141031
- break;
141032
- }
141033
- currentDir = parentDir;
141034
- }
141035
- return null;
141036
- }
141037
- function getCliPackageVersion(importMetaUrl = import.meta.url) {
141038
- const startDir = dirname15(fileURLToPath4(importMetaUrl));
141039
- return resolveCliPackageVersionInfo(startDir)?.version ?? process.env.npm_package_version ?? "0.0.0";
141040
- }
141041
- var CLI_PACKAGE_NAME;
141042
- var init_cli_package_version = __esm({
141043
- "../dashboard/src/cli-package-version.ts"() {
141044
- "use strict";
141045
- CLI_PACKAGE_NAME = "@runfusion/fusion";
141046
- }
141047
- });
141048
-
141049
141530
  // ../dashboard/src/routes/register-update-check-routes.ts
141050
141531
  var registerUpdateCheckRoutes;
141051
141532
  var init_register_update_check_routes = __esm({
@@ -145824,7 +146305,7 @@ function detectPortFromLogLine(line) {
145824
146305
  return detectViteLine(cleanLine) ?? detectNextLine(cleanLine) ?? detectStorybookLine(cleanLine) ?? detectAngularLine(cleanLine) ?? detectGenericUrl(cleanLine) ?? detectGenericPortLine(cleanLine);
145825
146306
  }
145826
146307
  function probePort(host, port, timeoutMs) {
145827
- return new Promise((resolve40) => {
146308
+ return new Promise((resolve42) => {
145828
146309
  let settled = false;
145829
146310
  const socket = createConnection({ host, port });
145830
146311
  const settle = (isOpen) => {
@@ -145838,7 +146319,7 @@ function probePort(host, port, timeoutMs) {
145838
146319
  } else {
145839
146320
  socket.destroy();
145840
146321
  }
145841
- resolve40(isOpen);
146322
+ resolve42(isOpen);
145842
146323
  };
145843
146324
  socket.setTimeout(timeoutMs);
145844
146325
  socket.once("connect", () => settle(true));
@@ -145879,7 +146360,7 @@ var init_dev_server_port_detect = __esm({
145879
146360
 
145880
146361
  // ../dashboard/src/dev-server-process.ts
145881
146362
  import { EventEmitter as EventEmitter34 } from "node:events";
145882
- import { spawn as spawn12 } from "node:child_process";
146363
+ import { spawn as spawn14 } from "node:child_process";
145883
146364
  function killManagedProcess2(child, signal) {
145884
146365
  if (typeof child.pid !== "number") {
145885
146366
  return;
@@ -145958,15 +146439,15 @@ var init_dev_server_process = __esm({
145958
146439
  detectedUrl: void 0,
145959
146440
  detectedPort: void 0
145960
146441
  });
145961
- const child = spawn12(safeCommand, [], {
146442
+ const child = spawn14(safeCommand, [], {
145962
146443
  cwd: safeCwd,
145963
146444
  detached: process.platform !== "win32",
145964
146445
  shell: true,
145965
146446
  stdio: ["pipe", "pipe", "pipe"]
145966
146447
  });
145967
146448
  this.childProcess = child;
145968
- this.closePromise = new Promise((resolve40) => {
145969
- this.resolveClosePromise = resolve40;
146449
+ this.closePromise = new Promise((resolve42) => {
146450
+ this.resolveClosePromise = resolve42;
145970
146451
  });
145971
146452
  const runningState = await this.store.updateState({
145972
146453
  pid: child.pid,
@@ -147592,6 +148073,7 @@ function createApiRoutes(store, options) {
147592
148073
  registerCustomProviderRoutes(routeContext);
147593
148074
  registerAuthRoutes(routeContext);
147594
148075
  registerRuntimeProviderRoutes(routeContext);
148076
+ registerFnBinaryRoutes(routeContext);
147595
148077
  router.post("/ai/refine-text", async (req, res) => {
147596
148078
  try {
147597
148079
  const { text, type } = req.body;
@@ -149182,15 +149664,15 @@ Description: ${step.description}`
149182
149664
  return;
149183
149665
  }
149184
149666
  }
149185
- const { resolve: resolve40, dirname: dirname29, join: join70 } = await import("node:path");
149667
+ const { resolve: resolve42, dirname: dirname30, join: join70 } = await import("node:path");
149186
149668
  const { readdir: readdir12, stat: stat12 } = await import("node:fs/promises");
149187
149669
  const rawPath = req.query.path || process.env.HOME || process.env.USERPROFILE || "/";
149188
149670
  const showHidden = req.query.showHidden === "true";
149189
- const resolvedPath = resolve40(rawPath);
149671
+ const resolvedPath = resolve42(rawPath);
149190
149672
  if (rawPath.includes("..")) {
149191
149673
  throw badRequest("Path must not contain '..' traversal");
149192
149674
  }
149193
- if (resolvedPath !== resolve40(resolvedPath)) {
149675
+ if (resolvedPath !== resolve42(resolvedPath)) {
149194
149676
  throw badRequest("Path must be absolute");
149195
149677
  }
149196
149678
  let pathStat;
@@ -149217,7 +149699,7 @@ Description: ${step.description}`
149217
149699
  entries.push({ name: entry.name, path: entryPath, hasChildren });
149218
149700
  }
149219
149701
  entries.sort((a, b) => a.name.localeCompare(b.name));
149220
- const parentPath = dirname29(resolvedPath) === resolvedPath ? null : dirname29(resolvedPath);
149702
+ const parentPath = dirname30(resolvedPath) === resolvedPath ? null : dirname30(resolvedPath);
149221
149703
  res.json({ currentPath: resolvedPath, parentPath, entries });
149222
149704
  } catch (err) {
149223
149705
  if (err instanceof ApiError) {
@@ -149727,6 +150209,7 @@ var init_routes = __esm({
149727
150209
  init_register_usage_routes();
149728
150210
  init_register_auth_routes();
149729
150211
  init_register_runtime_provider_routes();
150212
+ init_register_fn_binary_routes();
149730
150213
  init_register_update_check_routes();
149731
150214
  init_register_integrated_routers();
149732
150215
  init_resolve_diff_base();
@@ -156484,7 +156967,7 @@ var init_task_lifecycle = __esm({
156484
156967
  // src/commands/port-prompt.ts
156485
156968
  import { createInterface } from "node:readline";
156486
156969
  function promptForPort(defaultPort = 4040, input = process.stdin) {
156487
- return new Promise((resolve40, reject2) => {
156970
+ return new Promise((resolve42, reject2) => {
156488
156971
  const rl = createInterface({
156489
156972
  input,
156490
156973
  output: process.stdout
@@ -156501,7 +156984,7 @@ function promptForPort(defaultPort = 4040, input = process.stdin) {
156501
156984
  if (trimmed === "") {
156502
156985
  process.removeListener("SIGINT", sigintHandler);
156503
156986
  rl.close();
156504
- resolve40(defaultPort);
156987
+ resolve42(defaultPort);
156505
156988
  return;
156506
156989
  }
156507
156990
  const port = parseInt(trimmed, 10);
@@ -156517,7 +157000,7 @@ function promptForPort(defaultPort = 4040, input = process.stdin) {
156517
157000
  }
156518
157001
  process.removeListener("SIGINT", sigintHandler);
156519
157002
  rl.close();
156520
- resolve40(port);
157003
+ resolve42(port);
156521
157004
  });
156522
157005
  };
156523
157006
  ask();
@@ -157268,13 +157751,109 @@ var init_claude_cli_extension = __esm({
157268
157751
  }
157269
157752
  });
157270
157753
 
157754
+ // src/commands/droid-cli-extension.ts
157755
+ import { existsSync as existsSync40, readFileSync as readFileSync18 } from "node:fs";
157756
+ import { createRequire as createRequire5 } from "node:module";
157757
+ import { dirname as dirname24, resolve as resolve30 } from "node:path";
157758
+ import { fileURLToPath as fileURLToPath8 } from "node:url";
157759
+ function resolveDroidCliExtensionFromModuleUrl(moduleUrl) {
157760
+ let pkgJsonPath;
157761
+ const here = dirname24(fileURLToPath8(moduleUrl));
157762
+ for (const rel of ["droid-cli", "../droid-cli", "../../droid-cli"]) {
157763
+ const candidate = resolve30(here, rel, "package.json");
157764
+ if (existsSync40(candidate)) {
157765
+ pkgJsonPath = candidate;
157766
+ break;
157767
+ }
157768
+ }
157769
+ if (!pkgJsonPath) {
157770
+ try {
157771
+ pkgJsonPath = require_2.resolve("@fusion/droid-cli/package.json");
157772
+ } catch {
157773
+ return { status: "not-installed" };
157774
+ }
157775
+ }
157776
+ let pkgJson;
157777
+ try {
157778
+ pkgJson = JSON.parse(readFileSync18(pkgJsonPath, "utf-8"));
157779
+ } catch (err) {
157780
+ return {
157781
+ status: "error",
157782
+ reason: `Failed to read @fusion/droid-cli package.json: ${err instanceof Error ? err.message : String(err)}`
157783
+ };
157784
+ }
157785
+ const extensions = pkgJson.pi?.extensions;
157786
+ if (!Array.isArray(extensions) || extensions.length === 0) {
157787
+ return {
157788
+ status: "missing-entry",
157789
+ reason: "@fusion/droid-cli package.json has no pi.extensions array"
157790
+ };
157791
+ }
157792
+ const rawEntry = extensions[0];
157793
+ if (typeof rawEntry !== "string" || rawEntry.length === 0) {
157794
+ return {
157795
+ status: "missing-entry",
157796
+ reason: "@fusion/droid-cli pi.extensions[0] is not a valid path string"
157797
+ };
157798
+ }
157799
+ const entryPath = resolve30(dirname24(pkgJsonPath), rawEntry);
157800
+ if (!existsSync40(entryPath)) {
157801
+ return {
157802
+ status: "missing-entry",
157803
+ reason: `@fusion/droid-cli extension file not found at ${entryPath}`
157804
+ };
157805
+ }
157806
+ return {
157807
+ status: "ok",
157808
+ path: entryPath,
157809
+ packageVersion: pkgJson.version ?? "unknown"
157810
+ };
157811
+ }
157812
+ function resolveDroidCliExtension() {
157813
+ return resolveDroidCliExtensionFromModuleUrl(import.meta.url);
157814
+ }
157815
+ function resolveDroidCliExtensionPaths(globalSettings) {
157816
+ const enabled = globalSettings?.useDroidCli === true;
157817
+ if (!enabled) {
157818
+ return { paths: [], resolution: null };
157819
+ }
157820
+ const resolution = resolveDroidCliExtension();
157821
+ switch (resolution.status) {
157822
+ case "ok":
157823
+ return { paths: [resolution.path], resolution };
157824
+ case "not-installed":
157825
+ return {
157826
+ paths: [],
157827
+ resolution,
157828
+ warning: "useDroidCli is on but @fusion/droid-cli is not installed in node_modules. Run `pnpm install`."
157829
+ };
157830
+ case "missing-entry":
157831
+ case "error":
157832
+ return { paths: [], resolution, warning: resolution.reason };
157833
+ }
157834
+ }
157835
+ function setCachedDroidCliResolution(resolution) {
157836
+ cachedResolution2 = resolution;
157837
+ }
157838
+ function getCachedDroidCliResolution() {
157839
+ return cachedResolution2;
157840
+ }
157841
+ var require_2, cachedResolution2;
157842
+ var init_droid_cli_extension = __esm({
157843
+ "src/commands/droid-cli-extension.ts"() {
157844
+ "use strict";
157845
+ require_2 = createRequire5(import.meta.url);
157846
+ cachedResolution2 = null;
157847
+ }
157848
+ });
157849
+
157271
157850
  // src/update-cache.ts
157272
- import { readFileSync as readFileSync18 } from "node:fs";
157851
+ import { readFileSync as readFileSync19 } from "node:fs";
157273
157852
  import { join as join56 } from "node:path";
157274
157853
  function getCachedUpdateStatus(currentVersion) {
157275
157854
  try {
157276
157855
  const cachePath = join56(resolveGlobalDir(), "update-check.json");
157277
- const raw = readFileSync18(cachePath, "utf-8");
157856
+ const raw = readFileSync19(cachePath, "utf-8");
157278
157857
  const parsed = JSON.parse(raw);
157279
157858
  if (parsed.updateAvailable === true && typeof parsed.latestVersion === "string" && parsed.latestVersion.length > 0 && typeof parsed.currentVersion === "string" && parsed.currentVersion.length > 0) {
157280
157859
  if (typeof currentVersion === "string" && currentVersion.length > 0 && parsed.currentVersion !== currentVersion) {
@@ -157305,17 +157884,17 @@ var init_update_cache = __esm({
157305
157884
  });
157306
157885
 
157307
157886
  // src/commands/self-extension.ts
157308
- import { existsSync as existsSync40, readFileSync as readFileSync19 } from "node:fs";
157309
- import { dirname as dirname24, resolve as resolve30 } from "node:path";
157310
- import { fileURLToPath as fileURLToPath8 } from "node:url";
157887
+ import { existsSync as existsSync41, readFileSync as readFileSync20 } from "node:fs";
157888
+ import { dirname as dirname25, resolve as resolve31 } from "node:path";
157889
+ import { fileURLToPath as fileURLToPath9 } from "node:url";
157311
157890
  function resolveSelfExtension() {
157312
- const here = dirname24(fileURLToPath8(import.meta.url));
157891
+ const here = dirname25(fileURLToPath9(import.meta.url));
157313
157892
  let pkgDir;
157314
157893
  let cur = here;
157315
157894
  for (let i = 0; i < 5; i++) {
157316
- if (existsSync40(resolve30(cur, "package.json"))) {
157895
+ if (existsSync41(resolve31(cur, "package.json"))) {
157317
157896
  try {
157318
- const parsed = JSON.parse(readFileSync19(resolve30(cur, "package.json"), "utf-8"));
157897
+ const parsed = JSON.parse(readFileSync20(resolve31(cur, "package.json"), "utf-8"));
157319
157898
  if (parsed.name === "@runfusion/fusion") {
157320
157899
  pkgDir = cur;
157321
157900
  break;
@@ -157323,7 +157902,7 @@ function resolveSelfExtension() {
157323
157902
  } catch {
157324
157903
  }
157325
157904
  }
157326
- const parent2 = resolve30(cur, "..");
157905
+ const parent2 = resolve31(cur, "..");
157327
157906
  if (parent2 === cur) break;
157328
157907
  cur = parent2;
157329
157908
  }
@@ -157332,12 +157911,12 @@ function resolveSelfExtension() {
157332
157911
  }
157333
157912
  let pkgJson;
157334
157913
  try {
157335
- pkgJson = JSON.parse(readFileSync19(resolve30(pkgDir, "package.json"), "utf-8"));
157914
+ pkgJson = JSON.parse(readFileSync20(resolve31(pkgDir, "package.json"), "utf-8"));
157336
157915
  } catch (err) {
157337
157916
  return { status: "missing", reason: `Failed to read @runfusion/fusion package.json: ${err instanceof Error ? err.message : String(err)}` };
157338
157917
  }
157339
- const srcEntry = resolve30(pkgDir, "src", "extension.ts");
157340
- if (existsSync40(srcEntry)) {
157918
+ const srcEntry = resolve31(pkgDir, "src", "extension.ts");
157919
+ if (existsSync41(srcEntry)) {
157341
157920
  return { status: "ok", path: srcEntry, packageVersion: pkgJson.version ?? "unknown" };
157342
157921
  }
157343
157922
  const extensions = pkgJson.pi?.extensions;
@@ -157348,8 +157927,8 @@ function resolveSelfExtension() {
157348
157927
  if (typeof rawEntry !== "string" || rawEntry.length === 0) {
157349
157928
  return { status: "missing", reason: "@runfusion/fusion pi.extensions[0] is not a valid path string" };
157350
157929
  }
157351
- const entryPath = resolve30(pkgDir, rawEntry);
157352
- if (!existsSync40(entryPath)) {
157930
+ const entryPath = resolve31(pkgDir, rawEntry);
157931
+ if (!existsSync41(entryPath)) {
157353
157932
  return { status: "missing", reason: `@runfusion/fusion extension file not found at ${entryPath}` };
157354
157933
  }
157355
157934
  return { status: "ok", path: entryPath, packageVersion: pkgJson.version ?? "unknown" };
@@ -157561,7 +158140,7 @@ var init_use_projects = __esm({
157561
158140
  });
157562
158141
 
157563
158142
  // src/commands/dashboard-tui/utils.ts
157564
- import { spawn as spawn13 } from "node:child_process";
158143
+ import { spawn as spawn15 } from "node:child_process";
157565
158144
  function isTTYAvailable() {
157566
158145
  return Boolean(process.stdout.isTTY && process.stdin.isTTY);
157567
158146
  }
@@ -157572,14 +158151,14 @@ async function copyToClipboard(text) {
157572
158151
  { cmd: "xsel", args: ["--clipboard", "--input"] }
157573
158152
  ];
157574
158153
  for (const { cmd, args } of candidates) {
157575
- const ok = await new Promise((resolve40) => {
158154
+ const ok = await new Promise((resolve42) => {
157576
158155
  try {
157577
- const child = spawn13(cmd, args, { stdio: ["pipe", "ignore", "ignore"] });
157578
- child.once("error", () => resolve40(false));
157579
- child.once("close", (code) => resolve40(code === 0));
158156
+ const child = spawn15(cmd, args, { stdio: ["pipe", "ignore", "ignore"] });
158157
+ child.once("error", () => resolve42(false));
158158
+ child.once("close", (code) => resolve42(code === 0));
157580
158159
  child.stdin.end(text);
157581
158160
  } catch {
157582
- resolve40(false);
158161
+ resolve42(false);
157583
158162
  }
157584
158163
  });
157585
158164
  if (ok) return true;
@@ -157601,7 +158180,7 @@ import { useState as useState2, useSyncExternalStore, useCallback as useCallback
157601
158180
  import { Box, Text, useInput, useApp, useStdout } from "ink";
157602
158181
  import Spinner from "ink-spinner";
157603
158182
  import TextInput from "ink-text-input";
157604
- import { spawn as spawn14 } from "node:child_process";
158183
+ import { spawn as spawn16 } from "node:child_process";
157605
158184
  import { appendFileSync } from "node:fs";
157606
158185
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
157607
158186
  function tuiDebug(tag, data) {
@@ -157627,7 +158206,7 @@ function openInBrowser(url) {
157627
158206
  args = [url];
157628
158207
  }
157629
158208
  try {
157630
- const child = spawn14(cmd, args, { detached: true, stdio: "ignore" });
158209
+ const child = spawn16(cmd, args, { detached: true, stdio: "ignore" });
157631
158210
  child.unref();
157632
158211
  } catch {
157633
158212
  }
@@ -161640,8 +162219,8 @@ async function resolveCachedStartupUpdateStatus(importMetaUrl) {
161640
162219
  try {
161641
162220
  const updateCheckEnabled = await Promise.race([
161642
162221
  isUpdateCheckEnabled(),
161643
- new Promise((resolve40) => {
161644
- setTimeout(() => resolve40(false), 3e3);
162222
+ new Promise((resolve42) => {
162223
+ setTimeout(() => resolve42(false), 3e3);
161645
162224
  })
161646
162225
  ]);
161647
162226
  if (!updateCheckEnabled) {
@@ -162361,6 +162940,23 @@ async function runDashboard(port, opts = {}) {
162361
162940
  return [];
162362
162941
  }
162363
162942
  })();
162943
+ const droidCliPaths = await (async () => {
162944
+ try {
162945
+ const globalSettings = await store.getGlobalSettingsStore().getSettings();
162946
+ const result = resolveDroidCliExtensionPaths(globalSettings);
162947
+ setCachedDroidCliResolution(result.resolution);
162948
+ if (result.warning) {
162949
+ console.warn(`[extensions] droid-cli: ${result.warning}`);
162950
+ }
162951
+ return result.paths;
162952
+ } catch (err) {
162953
+ console.warn(
162954
+ `[extensions] Unable to evaluate useDroidCli setting: ${err instanceof Error ? err.message : String(err)}`
162955
+ );
162956
+ setCachedDroidCliResolution(null);
162957
+ return [];
162958
+ }
162959
+ })();
162364
162960
  const selfExtension = resolveSelfExtension();
162365
162961
  const selfExtensionPaths = selfExtension.status === "ok" ? [selfExtension.path] : [];
162366
162962
  if (selfExtension.status !== "ok") {
@@ -162372,7 +162968,8 @@ async function runDashboard(port, opts = {}) {
162372
162968
  ...selfExtensionPaths,
162373
162969
  ...getEnabledPiExtensionPaths(cwd),
162374
162970
  ...packageExtensionPaths,
162375
- ...claudeCliPaths
162971
+ ...claudeCliPaths,
162972
+ ...droidCliPaths
162376
162973
  ],
162377
162974
  cwd,
162378
162975
  join57(cwd, ".fusion", "disabled-auto-extension-discovery")
@@ -162569,6 +163166,17 @@ async function runDashboard(port, opts = {}) {
162569
163166
  }
162570
163167
  return { status: r.status, reason: r.reason };
162571
163168
  },
163169
+ getDroidCliExtensionStatus: () => {
163170
+ const r = getCachedDroidCliResolution();
163171
+ if (!r) return null;
163172
+ if (r.status === "ok") {
163173
+ return { status: "ok", path: r.path, packageVersion: r.packageVersion };
163174
+ }
163175
+ if (r.status === "not-installed") {
163176
+ return { status: "not-installed" };
163177
+ }
163178
+ return { status: r.status, reason: r.reason };
163179
+ },
162572
163180
  onUseClaudeCliToggled: (_prev, next) => {
162573
163181
  if (!next) return;
162574
163182
  void (async () => {
@@ -162586,6 +163194,11 @@ async function runDashboard(port, opts = {}) {
162586
163194
  }
162587
163195
  })();
162588
163196
  },
163197
+ onUseDroidCliToggled: (_prev, next) => {
163198
+ if (next) {
163199
+ logSink.log("Droid CLI enabled \u2014 restart required for full effect", "extensions");
163200
+ }
163201
+ },
162589
163202
  skillsAdapter,
162590
163203
  https: loadTlsCredentialsFromEnv(),
162591
163204
  daemon: dashboardAuthToken ? { token: dashboardAuthToken } : void 0,
@@ -162752,6 +163365,17 @@ async function runDashboard(port, opts = {}) {
162752
163365
  }
162753
163366
  return { status: r.status, reason: r.reason };
162754
163367
  },
163368
+ getDroidCliExtensionStatus: () => {
163369
+ const r = getCachedDroidCliResolution();
163370
+ if (!r) return null;
163371
+ if (r.status === "ok") {
163372
+ return { status: "ok", path: r.path, packageVersion: r.packageVersion };
163373
+ }
163374
+ if (r.status === "not-installed") {
163375
+ return { status: "not-installed" };
163376
+ }
163377
+ return { status: r.status, reason: r.reason };
163378
+ },
162755
163379
  onUseClaudeCliToggled: (_prev, next) => {
162756
163380
  if (!next) return;
162757
163381
  void (async () => {
@@ -162769,6 +163393,11 @@ async function runDashboard(port, opts = {}) {
162769
163393
  }
162770
163394
  })();
162771
163395
  },
163396
+ onUseDroidCliToggled: (_prev, next) => {
163397
+ if (next) {
163398
+ logSink.log("Droid CLI enabled \u2014 restart required for full effect", "extensions");
163399
+ }
163400
+ },
162772
163401
  skillsAdapter,
162773
163402
  https: loadTlsCredentialsFromEnv(),
162774
163403
  daemon: dashboardAuthToken ? { token: dashboardAuthToken } : void 0,
@@ -163345,6 +163974,7 @@ var init_dashboard = __esm({
163345
163974
  init_project_context();
163346
163975
  init_claude_skills_runner();
163347
163976
  init_claude_cli_extension();
163977
+ init_droid_cli_extension();
163348
163978
  init_update_cache();
163349
163979
  init_self_extension();
163350
163980
  init_custom_provider_registry();
@@ -164122,6 +164752,23 @@ async function runServe(port, opts = {}) {
164122
164752
  return [];
164123
164753
  }
164124
164754
  })();
164755
+ const droidCliPaths = await (async () => {
164756
+ try {
164757
+ const globalSettings = await store.getGlobalSettingsStore().getSettings();
164758
+ const result = resolveDroidCliExtensionPaths(globalSettings);
164759
+ setCachedDroidCliResolution(result.resolution);
164760
+ if (result.warning) {
164761
+ console.warn(`[extensions] droid-cli: ${result.warning}`);
164762
+ }
164763
+ return result.paths;
164764
+ } catch (err) {
164765
+ console.warn(
164766
+ `[extensions] Unable to evaluate useDroidCli setting: ${err instanceof Error ? err.message : String(err)}`
164767
+ );
164768
+ setCachedDroidCliResolution(null);
164769
+ return [];
164770
+ }
164771
+ })();
164125
164772
  const selfExtension = resolveSelfExtension();
164126
164773
  const selfExtensionPaths = selfExtension.status === "ok" ? [selfExtension.path] : [];
164127
164774
  if (selfExtension.status !== "ok") {
@@ -164133,7 +164780,8 @@ async function runServe(port, opts = {}) {
164133
164780
  ...selfExtensionPaths,
164134
164781
  ...getEnabledPiExtensionPaths(cwd),
164135
164782
  ...packageExtensionPaths,
164136
- ...claudeCliPaths
164783
+ ...claudeCliPaths,
164784
+ ...droidCliPaths
164137
164785
  ],
164138
164786
  cwd,
164139
164787
  join58(cwd, ".fusion", "disabled-auto-extension-discovery")
@@ -164292,6 +164940,17 @@ async function runServe(port, opts = {}) {
164292
164940
  }
164293
164941
  return { status: r.status, reason: r.reason };
164294
164942
  },
164943
+ getDroidCliExtensionStatus: () => {
164944
+ const r = getCachedDroidCliResolution();
164945
+ if (!r) return null;
164946
+ if (r.status === "ok") {
164947
+ return { status: "ok", path: r.path, packageVersion: r.packageVersion };
164948
+ }
164949
+ if (r.status === "not-installed") {
164950
+ return { status: "not-installed" };
164951
+ }
164952
+ return { status: r.status, reason: r.reason };
164953
+ },
164295
164954
  onUseClaudeCliToggled: (_prev, next) => {
164296
164955
  if (!next) return;
164297
164956
  void (async () => {
@@ -164308,14 +164967,19 @@ async function runServe(port, opts = {}) {
164308
164967
  }
164309
164968
  })();
164310
164969
  },
164970
+ onUseDroidCliToggled: (_prev, next) => {
164971
+ if (next) {
164972
+ console.log("[extensions] Droid CLI enabled \u2014 restart required for full effect");
164973
+ }
164974
+ },
164311
164975
  headless: true,
164312
164976
  skillsAdapter,
164313
164977
  daemon: daemonToken ? { token: daemonToken } : void 0,
164314
164978
  https: loadTlsCredentialsFromEnv()
164315
164979
  });
164316
164980
  const server = app.listen(selectedPort, selectedHost);
164317
- await new Promise((resolve40, reject2) => {
164318
- server.once("listening", resolve40);
164981
+ await new Promise((resolve42, reject2) => {
164982
+ server.once("listening", resolve42);
164319
164983
  server.once("error", reject2);
164320
164984
  });
164321
164985
  const actualPort = server.address().port;
@@ -164459,6 +165123,7 @@ var init_serve = __esm({
164459
165123
  init_project_context();
164460
165124
  init_claude_skills_runner();
164461
165125
  init_claude_cli_extension();
165126
+ init_droid_cli_extension();
164462
165127
  init_self_extension();
164463
165128
  init_custom_provider_registry();
164464
165129
  DIAGNOSTIC_INTERVAL_MS2 = 30 * 60 * 1e3;
@@ -164730,6 +165395,23 @@ async function runDaemon(opts = {}) {
164730
165395
  return [];
164731
165396
  }
164732
165397
  })();
165398
+ const droidCliPaths = await (async () => {
165399
+ try {
165400
+ const globalSettings = await store.getGlobalSettingsStore().getSettings();
165401
+ const result = resolveDroidCliExtensionPaths(globalSettings);
165402
+ setCachedDroidCliResolution(result.resolution);
165403
+ if (result.warning) {
165404
+ console.warn(`[extensions] droid-cli: ${result.warning}`);
165405
+ }
165406
+ return result.paths;
165407
+ } catch (err) {
165408
+ console.warn(
165409
+ `[extensions] Unable to evaluate useDroidCli setting: ${err instanceof Error ? err.message : String(err)}`
165410
+ );
165411
+ setCachedDroidCliResolution(null);
165412
+ return [];
165413
+ }
165414
+ })();
164733
165415
  const selfExtension = resolveSelfExtension();
164734
165416
  const selfExtensionPaths = selfExtension.status === "ok" ? [selfExtension.path] : [];
164735
165417
  if (selfExtension.status !== "ok") {
@@ -164741,7 +165423,7 @@ async function runDaemon(opts = {}) {
164741
165423
  claudeCliPaths[0] ?? null
164742
165424
  );
164743
165425
  const extensionsResult = await discoverAndLoadExtensions4(
164744
- reconciledExtensionPaths,
165426
+ [...reconciledExtensionPaths, ...droidCliPaths],
164745
165427
  cwd,
164746
165428
  join59(cwd, ".fusion", "disabled-auto-extension-discovery")
164747
165429
  );
@@ -164812,6 +165494,17 @@ async function runDaemon(opts = {}) {
164812
165494
  }
164813
165495
  return { status: r.status, reason: r.reason };
164814
165496
  },
165497
+ getDroidCliExtensionStatus: () => {
165498
+ const r = getCachedDroidCliResolution();
165499
+ if (!r) return null;
165500
+ if (r.status === "ok") {
165501
+ return { status: "ok", path: r.path, packageVersion: r.packageVersion };
165502
+ }
165503
+ if (r.status === "not-installed") {
165504
+ return { status: "not-installed" };
165505
+ }
165506
+ return { status: r.status, reason: r.reason };
165507
+ },
164815
165508
  onUseClaudeCliToggled: (_prev, next) => {
164816
165509
  if (!next) return;
164817
165510
  void (async () => {
@@ -164828,14 +165521,19 @@ async function runDaemon(opts = {}) {
164828
165521
  }
164829
165522
  })();
164830
165523
  },
165524
+ onUseDroidCliToggled: (_prev, next) => {
165525
+ if (next) {
165526
+ console.log("[extensions] Droid CLI enabled \u2014 restart required for full effect");
165527
+ }
165528
+ },
164831
165529
  headless: true,
164832
165530
  daemon: { token: daemonToken },
164833
165531
  skillsAdapter,
164834
165532
  https: loadTlsCredentialsFromEnv()
164835
165533
  });
164836
165534
  const server = app.listen(selectedPort, selectedHost);
164837
- await new Promise((resolve40, reject2) => {
164838
- server.once("listening", resolve40);
165535
+ await new Promise((resolve42, reject2) => {
165536
+ server.once("listening", resolve42);
164839
165537
  server.once("error", reject2);
164840
165538
  });
164841
165539
  const actualPort = server.address().port;
@@ -164929,6 +165627,7 @@ var init_daemon = __esm({
164929
165627
  init_provider_settings();
164930
165628
  init_claude_skills_runner();
164931
165629
  init_claude_cli_extension();
165630
+ init_droid_cli_extension();
164932
165631
  init_self_extension();
164933
165632
  init_provider_auth();
164934
165633
  init_auth_paths2();
@@ -164944,13 +165643,13 @@ var desktop_exports = {};
164944
165643
  __export(desktop_exports, {
164945
165644
  runDesktop: () => runDesktop
164946
165645
  });
164947
- import { spawn as spawn15 } from "node:child_process";
165646
+ import { spawn as spawn17 } from "node:child_process";
164948
165647
  import { once as once2 } from "node:events";
164949
165648
  import { join as join60 } from "node:path";
164950
- import { createRequire as createRequire5 } from "node:module";
165649
+ import { createRequire as createRequire6 } from "node:module";
164951
165650
  function runCommand(command, args, cwd) {
164952
- return new Promise((resolve40, reject2) => {
164953
- const child = spawn15(command, args, {
165651
+ return new Promise((resolve42, reject2) => {
165652
+ const child = spawn17(command, args, {
164954
165653
  cwd,
164955
165654
  stdio: "inherit",
164956
165655
  env: process.env
@@ -164958,7 +165657,7 @@ function runCommand(command, args, cwd) {
164958
165657
  child.on("error", (error) => reject2(error));
164959
165658
  child.on("exit", (code) => {
164960
165659
  if (code === 0) {
164961
- resolve40();
165660
+ resolve42();
164962
165661
  return;
164963
165662
  }
164964
165663
  reject2(new Error(`${command} ${args.join(" ")} exited with code ${code ?? "unknown"}`));
@@ -165001,8 +165700,8 @@ async function startDashboardRuntime(rootDir, paused) {
165001
165700
  };
165002
165701
  }
165003
165702
  async function closeDashboardRuntime(runtime) {
165004
- await new Promise((resolve40) => {
165005
- runtime.server.close(() => resolve40());
165703
+ await new Promise((resolve42) => {
165704
+ runtime.server.close(() => resolve42());
165006
165705
  });
165007
165706
  runtime.store.close();
165008
165707
  }
@@ -165035,7 +165734,7 @@ async function runDesktop(options = {}) {
165035
165734
  electronEnv.FUSION_DASHBOARD_URL = process.env.FUSION_DASHBOARD_URL ?? "http://localhost:5173";
165036
165735
  electronEnv.NODE_ENV = "development";
165037
165736
  }
165038
- const electronProcess = spawn15(electronBinary, electronArgs, {
165737
+ const electronProcess = spawn17(electronBinary, electronArgs, {
165039
165738
  cwd: rootDir,
165040
165739
  stdio: "inherit",
165041
165740
  env: electronEnv
@@ -165074,7 +165773,7 @@ var init_desktop = __esm({
165074
165773
  "use strict";
165075
165774
  init_src();
165076
165775
  init_src4();
165077
- require3 = createRequire5(import.meta.url);
165776
+ require3 = createRequire6(import.meta.url);
165078
165777
  }
165079
165778
  });
165080
165779
 
@@ -165110,7 +165809,7 @@ __export(task_exports, {
165110
165809
  runTaskUpdate: () => runTaskUpdate
165111
165810
  });
165112
165811
  import { createInterface as createInterface3 } from "node:readline/promises";
165113
- import { watchFile, unwatchFile, statSync as statSync6, existsSync as existsSync41, readFileSync as readFileSync20 } from "node:fs";
165812
+ import { watchFile, unwatchFile, statSync as statSync6, existsSync as existsSync42, readFileSync as readFileSync21 } from "node:fs";
165114
165813
  import { basename as basename17, join as join61 } from "node:path";
165115
165814
  function getGitHubIssueUrl(sourceMetadata) {
165116
165815
  if (!sourceMetadata || typeof sourceMetadata !== "object") return void 0;
@@ -165275,9 +165974,9 @@ async function runTaskCreate(descriptionArg, attachFiles, depends, projectName,
165275
165974
  console.log(` Path: .fusion/tasks/${task.id}/`);
165276
165975
  if (attachFiles && attachFiles.length > 0) {
165277
165976
  const { readFile: readFile24 } = await import("node:fs/promises");
165278
- const { basename: basename22, extname: extname3, resolve: resolve40 } = await import("node:path");
165977
+ const { basename: basename22, extname: extname3, resolve: resolve42 } = await import("node:path");
165279
165978
  for (const filePath of attachFiles) {
165280
- const resolvedPath = resolve40(filePath);
165979
+ const resolvedPath = resolve42(filePath);
165281
165980
  const filename = basename22(resolvedPath);
165282
165981
  const ext = extname3(filename).toLowerCase();
165283
165982
  const mimeType = MIME_TYPES[ext];
@@ -165412,7 +166111,7 @@ async function runTaskLogs(id, options = {}, projectName) {
165412
166111
  if (options.follow) {
165413
166112
  const projectPath = projectContext?.projectPath ?? process.cwd();
165414
166113
  const logPath = join61(projectPath, ".fusion", "tasks", id, "agent.log");
165415
- if (!existsSync41(logPath)) {
166114
+ if (!existsSync42(logPath)) {
165416
166115
  console.log(`
165417
166116
  Waiting for log file to be created...`);
165418
166117
  }
@@ -165441,7 +166140,7 @@ async function runTaskLogs(id, options = {}, projectName) {
165441
166140
  lastPosition = 0;
165442
166141
  }
165443
166142
  if (stats.size > lastPosition) {
165444
- const content = readFileSync20(logPath, "utf-8");
166143
+ const content = readFileSync21(logPath, "utf-8");
165445
166144
  const lines = content.slice(lastPosition).split("\n");
165446
166145
  for (const line of lines) {
165447
166146
  if (!line.trim()) continue;
@@ -165575,8 +166274,8 @@ async function runTaskMerge(id, projectName) {
165575
166274
  async function runTaskAttach(id, filePath, projectName) {
165576
166275
  const { readFile: readFile24 } = await import("node:fs/promises");
165577
166276
  const { basename: basename22, extname: extname3 } = await import("node:path");
165578
- const { resolve: resolve40 } = await import("node:path");
165579
- const resolvedPath = resolve40(filePath);
166277
+ const { resolve: resolve42 } = await import("node:path");
166278
+ const resolvedPath = resolve42(filePath);
165580
166279
  const filename = basename22(resolvedPath);
165581
166280
  const ext = extname3(filename).toLowerCase();
165582
166281
  const mimeType = MIME_TYPES[ext];
@@ -166115,12 +166814,12 @@ async function promptText(question) {
166115
166814
  console.log(" (Enter your response. Type DONE on its own line when finished):\n");
166116
166815
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
166117
166816
  const lines = [];
166118
- return new Promise((resolve40) => {
166817
+ return new Promise((resolve42) => {
166119
166818
  const askLine = () => {
166120
166819
  rl.question(" ").then((line) => {
166121
166820
  if (line.trim() === "DONE") {
166122
166821
  rl.close();
166123
- resolve40(lines.join("\n"));
166822
+ resolve42(lines.join("\n"));
166124
166823
  } else {
166125
166824
  lines.push(line);
166126
166825
  askLine();
@@ -166285,7 +166984,7 @@ async function runTaskPlan(initialPlanArg, yesFlag = false, projectName) {
166285
166984
  } catch (err) {
166286
166985
  clearThinking();
166287
166986
  if (err instanceof RateLimitError2) {
166288
- console.error("\n Rate limit exceeded. Maximum 5 planning sessions per hour.\n");
166987
+ console.error("\n Rate limit exceeded. Maximum 1000 planning sessions per hour.\n");
166289
166988
  process.exit(1);
166290
166989
  }
166291
166990
  console.error(`
@@ -166689,7 +167388,7 @@ __export(settings_export_exports, {
166689
167388
  runSettingsExport: () => runSettingsExport
166690
167389
  });
166691
167390
  import { writeFile as writeFile18 } from "node:fs/promises";
166692
- import { resolve as resolve31, join as join62 } from "node:path";
167391
+ import { resolve as resolve32, join as join62 } from "node:path";
166693
167392
  async function runSettingsExport(options = {}) {
166694
167393
  const scope = options.scope ?? "both";
166695
167394
  const project = options.projectName ? await resolveProject(options.projectName) : void 0;
@@ -166700,7 +167399,7 @@ async function runSettingsExport(options = {}) {
166700
167399
  const exportData = await exportSettings(store, { scope });
166701
167400
  let targetPath;
166702
167401
  if (outputPath) {
166703
- targetPath = resolve31(outputPath);
167402
+ targetPath = resolve32(outputPath);
166704
167403
  } else {
166705
167404
  const filename = generateExportFilename();
166706
167405
  targetPath = join62(process.cwd(), filename);
@@ -166749,8 +167448,8 @@ var settings_import_exports = {};
166749
167448
  __export(settings_import_exports, {
166750
167449
  runSettingsImport: () => runSettingsImport
166751
167450
  });
166752
- import { existsSync as existsSync42 } from "node:fs";
166753
- import { resolve as resolve32 } from "node:path";
167451
+ import { existsSync as existsSync43 } from "node:fs";
167452
+ import { resolve as resolve33 } from "node:path";
166754
167453
  async function runSettingsImport(filePath, options = {}) {
166755
167454
  const scope = options.scope ?? "both";
166756
167455
  const project = options.projectName ? await resolveProject(options.projectName) : void 0;
@@ -166759,8 +167458,8 @@ async function runSettingsImport(filePath, options = {}) {
166759
167458
  const merge = options.merge ?? true;
166760
167459
  const skipConfirm = options.yes ?? false;
166761
167460
  try {
166762
- const resolvedPath = resolve32(filePath);
166763
- if (!existsSync42(resolvedPath)) {
167461
+ const resolvedPath = resolve33(filePath);
167462
+ if (!existsSync43(resolvedPath)) {
166764
167463
  console.error(`Error: File not found: ${filePath}`);
166765
167464
  process.exit(1);
166766
167465
  }
@@ -167233,8 +167932,8 @@ var init_backup2 = __esm({
167233
167932
  });
167234
167933
 
167235
167934
  // src/project-resolver.ts
167236
- import { existsSync as existsSync43, statSync as statSync7 } from "node:fs";
167237
- import { basename as basename18, dirname as dirname25, resolve as resolve33, normalize as normalize5 } from "node:path";
167935
+ import { existsSync as existsSync44, statSync as statSync7 } from "node:fs";
167936
+ import { basename as basename18, dirname as dirname26, resolve as resolve34, normalize as normalize5 } from "node:path";
167238
167937
  import { createInterface as createInterface5 } from "node:readline/promises";
167239
167938
  async function getCentralCore() {
167240
167939
  if (!centralCoreInstance) {
@@ -167251,13 +167950,13 @@ async function getProjectManager() {
167251
167950
  return projectManagerInstance;
167252
167951
  }
167253
167952
  function findKbDir(startPath) {
167254
- let current = resolve33(startPath);
167953
+ let current = resolve34(startPath);
167255
167954
  for (let i = 0; i < 100; i++) {
167256
- const dbPath = resolve33(current, ".fusion", "fusion.db");
167955
+ const dbPath = resolve34(current, ".fusion", "fusion.db");
167257
167956
  if (isValidSqliteDatabaseFile(dbPath)) {
167258
167957
  return current;
167259
167958
  }
167260
- const parent2 = dirname25(current);
167959
+ const parent2 = dirname26(current);
167261
167960
  if (parent2 === current) {
167262
167961
  break;
167263
167962
  }
@@ -167309,7 +168008,7 @@ async function resolveProject2(options = {}) {
167309
168008
  { searchedName: options.project, availableProjects: projects.map((p) => p.name) }
167310
168009
  );
167311
168010
  }
167312
- if (!existsSync43(match.path)) {
168011
+ if (!existsSync44(match.path)) {
167313
168012
  throw new ProjectResolutionError(
167314
168013
  `Project "${match.name}" is registered but the directory no longer exists: ${match.path}
167315
168014
 
@@ -167320,14 +168019,14 @@ Run \`fn project remove ` + match.name + "` to clean up the registry entry.",
167320
168019
  }
167321
168020
  return createResolvedProject(match);
167322
168021
  }
167323
- const cwd = options.cwd ? resolve33(options.cwd) : process.cwd();
168022
+ const cwd = options.cwd ? resolve34(options.cwd) : process.cwd();
167324
168023
  const fusionDir = findKbDir(cwd);
167325
168024
  if (fusionDir) {
167326
168025
  const allProjects2 = await central.listProjects();
167327
168026
  const normalizedKbDir = normalize5(fusionDir);
167328
168027
  const match = allProjects2.find((p) => normalize5(p.path) === normalizedKbDir);
167329
168028
  if (match) {
167330
- if (!existsSync43(match.path)) {
168029
+ if (!existsSync44(match.path)) {
167331
168030
  throw new ProjectResolutionError(
167332
168031
  `Project "${match.name}" is registered but the directory no longer exists: ${match.path}
167333
168032
 
@@ -167392,7 +168091,7 @@ Run \`fn project add ` + fusionDir + "` to register it, or use --project <name>.
167392
168091
  }
167393
168092
  if (allProjects.length === 1) {
167394
168093
  const project = allProjects[0];
167395
- if (!existsSync43(project.path)) {
168094
+ if (!existsSync44(project.path)) {
167396
168095
  throw new ProjectResolutionError(
167397
168096
  `The only registered project "${project.name}" has a missing directory: ${project.path}
167398
168097
 
@@ -167832,8 +168531,8 @@ __export(project_exports, {
167832
168531
  runProjectSetDefault: () => runProjectSetDefault,
167833
168532
  runProjectShow: () => runProjectShow
167834
168533
  });
167835
- import { resolve as resolve34, isAbsolute as isAbsolute19, relative as relative14, basename as basename19 } from "node:path";
167836
- import { existsSync as existsSync44, statSync as statSync8 } from "node:fs";
168534
+ import { resolve as resolve35, isAbsolute as isAbsolute19, relative as relative14, basename as basename19 } from "node:path";
168535
+ import { existsSync as existsSync45, statSync as statSync8 } from "node:fs";
167837
168536
  import { createInterface as createInterface7 } from "node:readline/promises";
167838
168537
  function formatDisplayPath(projectPath) {
167839
168538
  const rel = relative14(process.cwd(), projectPath);
@@ -167961,8 +168660,8 @@ async function runProjectAdd(name, path5, options = {}) {
167961
168660
  const pathInput = await rl.question(` Project path [${defaultPath}]: `);
167962
168661
  projectPath = pathInput.trim() || defaultPath;
167963
168662
  }
167964
- const absolutePath2 = isAbsolute19(projectPath) ? projectPath : resolve34(process.cwd(), projectPath);
167965
- if (!existsSync44(absolutePath2)) {
168663
+ const absolutePath2 = isAbsolute19(projectPath) ? projectPath : resolve35(process.cwd(), projectPath);
168664
+ if (!existsSync45(absolutePath2)) {
167966
168665
  console.error(`
167967
168666
  \u2717 Path does not exist: ${projectPath}`);
167968
168667
  rl.close();
@@ -167974,8 +168673,8 @@ async function runProjectAdd(name, path5, options = {}) {
167974
168673
  rl.close();
167975
168674
  process.exit(1);
167976
168675
  }
167977
- const kbDbPath2 = resolve34(absolutePath2, ".fusion", "fusion.db");
167978
- if (!existsSync44(kbDbPath2) && !options.force) {
168676
+ const kbDbPath2 = resolve35(absolutePath2, ".fusion", "fusion.db");
168677
+ if (!existsSync45(kbDbPath2) && !options.force) {
167979
168678
  console.log(`
167980
168679
  No fn project found at ${formatDisplayPath(absolutePath2)}`);
167981
168680
  const init = await rl.question(" Initialize fn here first? [Y/n] ");
@@ -168006,8 +168705,8 @@ async function runProjectAdd(name, path5, options = {}) {
168006
168705
  console.error(" Name must be 1-64 characters and contain only: a-z, A-Z, 0-9, _, -\n");
168007
168706
  process.exit(1);
168008
168707
  }
168009
- const absolutePath = isAbsolute19(projectPath) ? projectPath : resolve34(process.cwd(), projectPath);
168010
- if (!existsSync44(absolutePath)) {
168708
+ const absolutePath = isAbsolute19(projectPath) ? projectPath : resolve35(process.cwd(), projectPath);
168709
+ if (!existsSync45(absolutePath)) {
168011
168710
  console.error(`
168012
168711
  \u2717 Path does not exist: ${projectPath}
168013
168712
  `);
@@ -168019,8 +168718,8 @@ async function runProjectAdd(name, path5, options = {}) {
168019
168718
  `);
168020
168719
  process.exit(1);
168021
168720
  }
168022
- const kbDbPath = resolve34(absolutePath, ".fusion", "fusion.db");
168023
- if (!existsSync44(kbDbPath) && !options.force) {
168721
+ const kbDbPath = resolve35(absolutePath, ".fusion", "fusion.db");
168722
+ if (!existsSync45(kbDbPath) && !options.force) {
168024
168723
  console.error(`
168025
168724
  \u2717 No fn project found at ${formatDisplayPath(absolutePath)}`);
168026
168725
  console.error(" Run `fn init` first to initialize the project.\n");
@@ -168276,10 +168975,10 @@ var init_project = __esm({
168276
168975
  });
168277
168976
 
168278
168977
  // src/commands/skill-installation.ts
168279
- import { cpSync as cpSync2, existsSync as existsSync45, mkdirSync as mkdirSync8 } from "node:fs";
168978
+ import { cpSync as cpSync2, existsSync as existsSync46, mkdirSync as mkdirSync8 } from "node:fs";
168280
168979
  import { homedir as homedir10 } from "node:os";
168281
- import { dirname as dirname26, join as join63, resolve as resolve35 } from "node:path";
168282
- import { fileURLToPath as fileURLToPath9 } from "node:url";
168980
+ import { dirname as dirname27, join as join63, resolve as resolve36 } from "node:path";
168981
+ import { fileURLToPath as fileURLToPath10 } from "node:url";
168283
168982
  function getSupportedSkillInstallTargets(homeDir = process.env.HOME || process.env.USERPROFILE || homedir10()) {
168284
168983
  return [
168285
168984
  { client: "claude", targetDir: join63(homeDir, ".claude", "skills", FUSION_SKILL_NAME2) },
@@ -168288,9 +168987,9 @@ function getSupportedSkillInstallTargets(homeDir = process.env.HOME || process.e
168288
168987
  ];
168289
168988
  }
168290
168989
  function resolveBundledFusionSkillSource() {
168291
- const here = fileURLToPath9(import.meta.url);
168292
- const source = resolve35(dirname26(here), "..", "..", "skill", FUSION_SKILL_NAME2);
168293
- return existsSync45(source) ? source : null;
168990
+ const here = fileURLToPath10(import.meta.url);
168991
+ const source = resolve36(dirname27(here), "..", "..", "skill", FUSION_SKILL_NAME2);
168992
+ return existsSync46(source) ? source : null;
168294
168993
  }
168295
168994
  function installBundledFusionSkill(options = {}) {
168296
168995
  const sourceDir = options.sourceDir ?? resolveBundledFusionSkillSource();
@@ -168308,7 +169007,7 @@ function installBundledFusionSkill(options = {}) {
168308
169007
  }
168309
169008
  const results = targets.map((target) => {
168310
169009
  try {
168311
- if (existsSync45(target.targetDir)) {
169010
+ if (existsSync46(target.targetDir)) {
168312
169011
  return {
168313
169012
  client: target.client,
168314
169013
  targetDir: target.targetDir,
@@ -168316,7 +169015,7 @@ function installBundledFusionSkill(options = {}) {
168316
169015
  reason: "existing install preserved"
168317
169016
  };
168318
169017
  }
168319
- mkdirSync8(dirname26(target.targetDir), { recursive: true });
169018
+ mkdirSync8(dirname27(target.targetDir), { recursive: true });
168320
169019
  cpSync2(sourceDir, target.targetDir, { recursive: true });
168321
169020
  return {
168322
169021
  client: target.client,
@@ -168347,17 +169046,17 @@ var init_exports = {};
168347
169046
  __export(init_exports, {
168348
169047
  runInit: () => runInit
168349
169048
  });
168350
- import { existsSync as existsSync46, mkdirSync as mkdirSync9, writeFileSync as writeFileSync3, readFileSync as readFileSync21 } from "node:fs";
168351
- import { join as join64, resolve as resolve36, basename as basename20 } from "node:path";
169049
+ import { existsSync as existsSync47, mkdirSync as mkdirSync9, writeFileSync as writeFileSync3, readFileSync as readFileSync22 } from "node:fs";
169050
+ import { join as join64, resolve as resolve37, basename as basename20 } from "node:path";
168352
169051
  import { exec as exec12 } from "node:child_process";
168353
169052
  import { promisify as promisify17 } from "node:util";
168354
169053
  async function runInit(options = {}) {
168355
- const cwd = options.path ? resolve36(options.path) : process.cwd();
169054
+ const cwd = options.path ? resolve37(options.path) : process.cwd();
168356
169055
  const fusionDir = join64(cwd, ".fusion");
168357
169056
  const dbPath = join64(fusionDir, "fusion.db");
168358
- const hasDbPath = existsSync46(dbPath);
169057
+ const hasDbPath = existsSync47(dbPath);
168359
169058
  const hasValidDb = hasDbPath && isValidSqliteDatabaseFile(dbPath);
168360
- if (existsSync46(fusionDir) && hasDbPath && hasValidDb) {
169059
+ if (existsSync47(fusionDir) && hasDbPath && hasValidDb) {
168361
169060
  const central2 = new CentralCore();
168362
169061
  await central2.init();
168363
169062
  const existing = await central2.getProjectByPath(cwd);
@@ -168379,7 +169078,7 @@ async function runInit(options = {}) {
168379
169078
  await central2.close();
168380
169079
  return;
168381
169080
  }
168382
- if (existsSync46(fusionDir) && hasDbPath && !hasValidDb) {
169081
+ if (existsSync47(fusionDir) && hasDbPath && !hasValidDb) {
168383
169082
  throw new Error(
168384
169083
  `Existing database at ${dbPath} is not a valid SQLite database. Restore it from .fusion/backups or move it aside before re-running fn init.`
168385
169084
  );
@@ -168387,7 +169086,7 @@ async function runInit(options = {}) {
168387
169086
  const projectName = options.name ?? await detectProjectName(cwd);
168388
169087
  console.log(`Initializing fn project: "${projectName}"`);
168389
169088
  console.log(` Path: ${cwd}`);
168390
- if (!existsSync46(fusionDir)) {
169089
+ if (!existsSync47(fusionDir)) {
168391
169090
  mkdirSync9(fusionDir, { recursive: true });
168392
169091
  console.log(` \u2713 Created .fusion/ directory`);
168393
169092
  }
@@ -168400,7 +169099,7 @@ async function runInit(options = {}) {
168400
169099
  }
168401
169100
  await addLocalStorageToGitignore(cwd);
168402
169101
  await warnIfQmdMissing();
168403
- if (!existsSync46(dbPath)) {
169102
+ if (!existsSync47(dbPath)) {
168404
169103
  writeFileSync3(dbPath, "");
168405
169104
  console.log(` \u2713 Created fusion.db`);
168406
169105
  }
@@ -168450,7 +169149,7 @@ async function runInit(options = {}) {
168450
169149
  }
168451
169150
  }
168452
169151
  async function detectProjectName(dir2) {
168453
- if (!existsSync46(join64(dir2, ".git"))) {
169152
+ if (!existsSync47(join64(dir2, ".git"))) {
168454
169153
  return basename20(dir2) || "my-project";
168455
169154
  }
168456
169155
  try {
@@ -168472,9 +169171,9 @@ async function detectProjectName(dir2) {
168472
169171
  async function addLocalStorageToGitignore(cwd) {
168473
169172
  const gitignorePath = join64(cwd, ".gitignore");
168474
169173
  let content = "";
168475
- if (existsSync46(gitignorePath)) {
169174
+ if (existsSync47(gitignorePath)) {
168476
169175
  try {
168477
- content = readFileSync21(gitignorePath, "utf-8");
169176
+ content = readFileSync22(gitignorePath, "utf-8");
168478
169177
  } catch {
168479
169178
  }
168480
169179
  }
@@ -168514,7 +169213,7 @@ async function initializeGitRepo(cwd) {
168514
169213
  await ensureGitConfig(cwd, "user.name", "Fusion");
168515
169214
  await ensureGitConfig(cwd, "user.email", "noreply@runfusion.ai");
168516
169215
  const gitkeepPath = join64(cwd, ".gitkeep");
168517
- if (!existsSync46(gitkeepPath)) {
169216
+ if (!existsSync47(gitkeepPath)) {
168518
169217
  writeFileSync3(gitkeepPath, "\n");
168519
169218
  }
168520
169219
  await execAsync11("git add .gitkeep", { cwd, timeout: 1e4 });
@@ -168652,8 +169351,8 @@ var agent_import_exports = {};
168652
169351
  __export(agent_import_exports, {
168653
169352
  runAgentImport: () => runAgentImport
168654
169353
  });
168655
- import { existsSync as existsSync47, mkdirSync as mkdirSync10, readFileSync as readFileSync22, statSync as statSync9, writeFileSync as writeFileSync4 } from "node:fs";
168656
- import { resolve as resolve37 } from "node:path";
169354
+ import { existsSync as existsSync48, mkdirSync as mkdirSync10, readFileSync as readFileSync23, statSync as statSync9, writeFileSync as writeFileSync4 } from "node:fs";
169355
+ import { resolve as resolve38 } from "node:path";
168657
169356
  function slugifyPathSegment(input) {
168658
169357
  if (!input || typeof input !== "string") {
168659
169358
  return "unnamed";
@@ -168702,16 +169401,16 @@ async function importSkillsToProject(projectPath, skills, companySlug, dryRun) {
168702
169401
  errors: []
168703
169402
  };
168704
169403
  const companyDir = slugifyPathSegment(companySlug ?? "unknown-company");
168705
- const baseSkillsDir = resolve37(projectPath, "skills", "imported", companyDir);
169404
+ const baseSkillsDir = resolve38(projectPath, "skills", "imported", companyDir);
168706
169405
  for (const skill of skills) {
168707
169406
  if (!skill.name || typeof skill.name !== "string" || skill.name.trim().length === 0) {
168708
169407
  result.errors.push({ name: "(unnamed)", error: "Skill is missing required 'name' field" });
168709
169408
  continue;
168710
169409
  }
168711
169410
  const skillSlug = slugifyPathSegment(skill.name);
168712
- const skillDir = resolve37(baseSkillsDir, skillSlug);
168713
- const skillPath = resolve37(skillDir, "SKILL.md");
168714
- if (existsSync47(skillPath)) {
169411
+ const skillDir = resolve38(baseSkillsDir, skillSlug);
169412
+ const skillPath = resolve38(skillDir, "SKILL.md");
169413
+ if (existsSync48(skillPath)) {
168715
169414
  result.skipped.push(skill.name);
168716
169415
  continue;
168717
169416
  }
@@ -168783,8 +169482,8 @@ function isArchivePath(path5) {
168783
169482
  async function runAgentImport(source, options) {
168784
169483
  const dryRun = options?.dryRun ?? false;
168785
169484
  const skipExisting = options?.skipExisting ?? false;
168786
- const sourcePath = resolve37(source);
168787
- if (!existsSync47(sourcePath)) {
169485
+ const sourcePath = resolve38(source);
169486
+ if (!existsSync48(sourcePath)) {
168788
169487
  console.error(`Path not found: ${sourcePath}`);
168789
169488
  process.exit(1);
168790
169489
  }
@@ -168830,7 +169529,7 @@ async function runAgentImport(source, options) {
168830
169529
  isPackageImport = true;
168831
169530
  ({ items: importItems, result } = prepareAgentCompaniesImport(pkg, conversionOptions));
168832
169531
  } else if (sourcePath.endsWith(".md")) {
168833
- const content = readFileSync22(sourcePath, "utf-8");
169532
+ const content = readFileSync23(sourcePath, "utf-8");
168834
169533
  const { manifest } = parseSingleAgentManifest(content);
168835
169534
  const pkg = {
168836
169535
  company: void 0,
@@ -168922,7 +169621,7 @@ var agent_export_exports = {};
168922
169621
  __export(agent_export_exports, {
168923
169622
  runAgentExport: () => runAgentExport
168924
169623
  });
168925
- import { resolve as resolve38 } from "node:path";
169624
+ import { resolve as resolve39 } from "node:path";
168926
169625
  async function getProjectPath4(projectName) {
168927
169626
  if (projectName) {
168928
169627
  const context = await resolveProject(projectName);
@@ -168960,7 +169659,7 @@ async function runAgentExport(outputDir, options) {
168960
169659
  console.error("No agents found to export");
168961
169660
  process.exit(1);
168962
169661
  }
168963
- const result = await exportAgentsToDirectory(agents, resolve38(outputDir), {
169662
+ const result = await exportAgentsToDirectory(agents, resolve39(outputDir), {
168964
169663
  companyName: options?.companyName,
168965
169664
  companySlug: options?.companySlug
168966
169665
  });
@@ -169179,7 +169878,7 @@ __export(plugin_exports, {
169179
169878
  runPluginList: () => runPluginList,
169180
169879
  runPluginUninstall: () => runPluginUninstall
169181
169880
  });
169182
- import { existsSync as existsSync48 } from "node:fs";
169881
+ import { existsSync as existsSync49 } from "node:fs";
169183
169882
  import { join as join65 } from "node:path";
169184
169883
  import { readFile as readFile23 } from "node:fs/promises";
169185
169884
  import * as readline from "node:readline";
@@ -169219,7 +169918,7 @@ async function createPluginLoader(pluginStore, projectName) {
169219
169918
  }
169220
169919
  async function loadManifestFromPath(pluginPath) {
169221
169920
  const manifestPath = join65(pluginPath, "manifest.json");
169222
- if (!existsSync48(manifestPath)) {
169921
+ if (!existsSync49(manifestPath)) {
169223
169922
  throw new Error(`Plugin manifest not found at: ${manifestPath}`);
169224
169923
  }
169225
169924
  const content = await readFile23(manifestPath, "utf-8");
@@ -169277,7 +169976,7 @@ async function runPluginInstall(source, options) {
169277
169976
  console.error("Please provide a local path to the plugin directory.");
169278
169977
  process.exit(1);
169279
169978
  }
169280
- if (!existsSync48(source)) {
169979
+ if (!existsSync49(source)) {
169281
169980
  console.error(`Plugin path does not exist: ${source}`);
169282
169981
  process.exit(1);
169283
169982
  }
@@ -169322,14 +170021,14 @@ async function runPluginUninstall(id, options) {
169322
170021
  console.log(` Uninstall "${plugin4.name}"?`);
169323
170022
  console.log(` This will stop and remove the plugin.`);
169324
170023
  console.log();
169325
- const response = await new Promise((resolve40) => {
170024
+ const response = await new Promise((resolve42) => {
169326
170025
  const rl = readline.createInterface({
169327
170026
  input: process.stdin,
169328
170027
  output: process.stdout
169329
170028
  });
169330
170029
  rl.question(" Continue? [y/N] ", (answer) => {
169331
170030
  rl.close();
169332
- resolve40(answer.toLowerCase());
170031
+ resolve42(answer.toLowerCase());
169333
170032
  });
169334
170033
  });
169335
170034
  if (response !== "y" && response !== "yes") {
@@ -169409,7 +170108,7 @@ var plugin_scaffold_exports = {};
169409
170108
  __export(plugin_scaffold_exports, {
169410
170109
  runPluginCreate: () => runPluginCreate
169411
170110
  });
169412
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync5, existsSync as existsSync49 } from "node:fs";
170111
+ import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync5, existsSync as existsSync50 } from "node:fs";
169413
170112
  import { join as join66 } from "node:path";
169414
170113
  function toTitleCase(str) {
169415
170114
  return str.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
@@ -169544,7 +170243,7 @@ async function runPluginCreate(name, options) {
169544
170243
  }
169545
170244
  const targetDir = options?.output ?? name;
169546
170245
  const targetPath = join66(process.cwd(), targetDir);
169547
- if (existsSync49(targetPath)) {
170246
+ if (existsSync50(targetPath)) {
169548
170247
  console.error(`Error: Directory '${targetDir}' already exists.`);
169549
170248
  console.error("Please choose a different name or remove the existing directory.");
169550
170249
  process.exit(1);
@@ -169594,7 +170293,7 @@ __export(skills_exports, {
169594
170293
  runSkillsSearch: () => runSkillsSearch,
169595
170294
  searchSkills: () => searchSkills
169596
170295
  });
169597
- import { spawn as spawn16 } from "node:child_process";
170296
+ import { spawn as spawn18 } from "node:child_process";
169598
170297
  async function searchSkills(query, limit = 10) {
169599
170298
  const url = `${SKILLS_API_BASE}/api/search?q=${encodeURIComponent(query)}&limit=${limit}`;
169600
170299
  try {
@@ -169672,14 +170371,14 @@ async function runSkillsInstall(args, options) {
169672
170371
  npxArgs.push("--skill", options.skill);
169673
170372
  }
169674
170373
  npxArgs.push("-y", "-a", "pi");
169675
- const child = spawn16("npx", npxArgs, {
170374
+ const child = spawn18("npx", npxArgs, {
169676
170375
  cwd: process.cwd(),
169677
170376
  stdio: "inherit",
169678
170377
  shell: true
169679
170378
  });
169680
- const exitCode = await new Promise((resolve40, reject2) => {
170379
+ const exitCode = await new Promise((resolve42, reject2) => {
169681
170380
  child.on("exit", (code) => {
169682
- resolve40(code ?? 1);
170381
+ resolve42(code ?? 1);
169683
170382
  });
169684
170383
  child.on("error", (err) => {
169685
170384
  reject2(err);
@@ -169712,7 +170411,7 @@ __export(research_exports, {
169712
170411
  runResearchShow: () => runResearchShow
169713
170412
  });
169714
170413
  import { writeFile as writeFile19 } from "node:fs/promises";
169715
- import { join as join67, resolve as resolve39 } from "node:path";
170414
+ import { join as join67, resolve as resolve40 } from "node:path";
169716
170415
  async function getStore3(projectName) {
169717
170416
  const project = projectName ? await resolveProject(projectName) : void 0;
169718
170417
  const store = new TaskStore(project?.projectPath ?? process.cwd());
@@ -169868,7 +170567,7 @@ async function runResearchExport(options) {
169868
170567
  }
169869
170568
  const content = format === "json" ? JSON.stringify(run, null, 2) : renderMarkdown(run);
169870
170569
  const ext = format === "json" ? "json" : "md";
169871
- const outputPath = options.output ? resolve39(options.output) : join67(process.cwd(), `research-${run.id.toLowerCase()}.${ext}`);
170570
+ const outputPath = options.output ? resolve40(options.output) : join67(process.cwd(), `research-${run.id.toLowerCase()}.${ext}`);
169872
170571
  await writeFile19(outputPath, content, "utf8");
169873
170572
  store.getResearchStore().createExport(run.id, format, content);
169874
170573
  if (options.json) {
@@ -169933,21 +170632,21 @@ __export(native_patch_exports, {
169933
170632
  isTerminalAvailable: () => isTerminalAvailable,
169934
170633
  setupNativeResolution: () => setupNativeResolution
169935
170634
  });
169936
- import { join as join68, basename as basename21, dirname as dirname27 } from "node:path";
169937
- import { existsSync as existsSync50, copyFileSync, mkdirSync as mkdirSync12, symlinkSync as symlinkSync2, rmSync as rmSync5, lstatSync as lstatSync3, readlinkSync as readlinkSync2 } from "node:fs";
170635
+ import { join as join68, basename as basename21, dirname as dirname28 } from "node:path";
170636
+ import { existsSync as existsSync51, copyFileSync, mkdirSync as mkdirSync12, symlinkSync as symlinkSync2, rmSync as rmSync5, lstatSync as lstatSync3, readlinkSync as readlinkSync2 } from "node:fs";
169938
170637
  import { tmpdir as tmpdir4 } from "node:os";
169939
170638
  function findStagedNativeDir2() {
169940
- const platform3 = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : process.platform === "win32" ? "win32" : "unknown";
170639
+ const platform4 = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : process.platform === "win32" ? "win32" : "unknown";
169941
170640
  const arch = process.arch === "arm64" ? "arm64" : process.arch === "x64" ? "x64" : "unknown";
169942
- const prebuildName = `${platform3}-${arch}`;
169943
- const execDir = dirname27(process.execPath);
170641
+ const prebuildName = `${platform4}-${arch}`;
170642
+ const execDir = dirname28(process.execPath);
169944
170643
  const nextToBinary = join68(execDir, "runtime", prebuildName);
169945
- if (existsSync50(join68(nextToBinary, "pty.node"))) {
170644
+ if (existsSync51(join68(nextToBinary, "pty.node"))) {
169946
170645
  return nextToBinary;
169947
170646
  }
169948
170647
  if (process.env.FUSION_RUNTIME_DIR) {
169949
170648
  const envPath = join68(process.env.FUSION_RUNTIME_DIR, prebuildName);
169950
- if (existsSync50(join68(envPath, "pty.node"))) {
170649
+ if (existsSync51(join68(envPath, "pty.node"))) {
169951
170650
  return envPath;
169952
170651
  }
169953
170652
  }
@@ -169957,11 +170656,11 @@ function cleanupStaleBunfsLinks() {
169957
170656
  if (process.platform === "win32") return;
169958
170657
  const bunfsRoot = "/$bunfs/root";
169959
170658
  try {
169960
- if (existsSync50(bunfsRoot)) {
170659
+ if (existsSync51(bunfsRoot)) {
169961
170660
  const stats = lstatSync3(bunfsRoot);
169962
170661
  if (stats.isSymbolicLink()) {
169963
170662
  const target = readlinkSync2(bunfsRoot);
169964
- if (target.includes("fn-bunfs-") && !existsSync50(target)) {
170663
+ if (target.includes("fn-bunfs-") && !existsSync51(target)) {
169965
170664
  rmSync5(bunfsRoot);
169966
170665
  console.log("[fn-native-patch] Cleaned up stale /$bunfs/root symlink");
169967
170666
  }
@@ -169989,14 +170688,14 @@ function setupNativeResolution() {
169989
170688
  mkdirSync12(platformDir, { recursive: true });
169990
170689
  const ptyNodeDest = join68(platformDir, "pty.node");
169991
170690
  copyFileSync(join68(nativeDir, "pty.node"), ptyNodeDest);
169992
- if (existsSync50(join68(nativeDir, "spawn-helper"))) {
170691
+ if (existsSync51(join68(nativeDir, "spawn-helper"))) {
169993
170692
  copyFileSync(join68(nativeDir, "spawn-helper"), join68(platformDir, "spawn-helper"));
169994
170693
  }
169995
170694
  process.env.FUSION_FAKE_BUNFS_ROOT = tmpRoot;
169996
170695
  if (process.platform !== "win32") {
169997
170696
  const bunfsRoot = "/$bunfs/root";
169998
170697
  try {
169999
- if (existsSync50(bunfsRoot)) {
170698
+ if (existsSync51(bunfsRoot)) {
170000
170699
  const stats = lstatSync3(bunfsRoot);
170001
170700
  if (stats.isSymbolicLink()) {
170002
170701
  rmSync5(bunfsRoot);
@@ -170019,7 +170718,7 @@ function setupNativeResolution() {
170019
170718
  function cleanupNativeResolution() {
170020
170719
  if (bunfsSymlinkPath && process.platform !== "win32") {
170021
170720
  try {
170022
- if (existsSync50(bunfsSymlinkPath)) {
170721
+ if (existsSync51(bunfsSymlinkPath)) {
170023
170722
  const stats = lstatSync3(bunfsSymlinkPath);
170024
170723
  if (stats.isSymbolicLink()) {
170025
170724
  rmSync5(bunfsSymlinkPath);
@@ -170065,11 +170764,12 @@ var init_native_patch = __esm({
170065
170764
  });
170066
170765
 
170067
170766
  // src/bin.ts
170068
- import { existsSync as existsSync51, mkdtempSync as mkdtempSync2, readFileSync as readFileSync23, symlinkSync as symlinkSync3, writeFileSync as writeFileSync6 } from "node:fs";
170069
- import { createRequire as createRequire6 } from "node:module";
170070
- import { join as join69, dirname as dirname28 } from "node:path";
170767
+ import { existsSync as existsSync52, mkdtempSync as mkdtempSync2, readFileSync as readFileSync24, symlinkSync as symlinkSync3, writeFileSync as writeFileSync6 } from "node:fs";
170768
+ import { createRequire as createRequire7 } from "node:module";
170769
+ import { join as join69, dirname as dirname29, resolve as resolve41 } from "node:path";
170071
170770
  import { tmpdir as tmpdir5 } from "node:os";
170072
170771
  import { performance as performance3 } from "node:perf_hooks";
170772
+ import { fileURLToPath as fileURLToPath11 } from "node:url";
170073
170773
  var isBunBinary3 = typeof Bun !== "undefined" && !!Bun.embeddedFiles;
170074
170774
  function configurePiPackage() {
170075
170775
  if (process.env.PI_PACKAGE_DIR) {
@@ -170082,13 +170782,13 @@ function configurePiPackage() {
170082
170782
  type: "module"
170083
170783
  };
170084
170784
  try {
170085
- const require4 = createRequire6(import.meta.url);
170785
+ const require4 = createRequire7(import.meta.url);
170086
170786
  const piPackagePath = require4.resolve("@mariozechner/pi-coding-agent/package.json");
170087
- const piPackageDir = dirname28(piPackagePath);
170088
- packageJson = JSON.parse(readFileSync23(piPackagePath, "utf-8"));
170787
+ const piPackageDir = dirname29(piPackagePath);
170788
+ packageJson = JSON.parse(readFileSync24(piPackagePath, "utf-8"));
170089
170789
  for (const entry of ["dist", "docs", "examples", "README.md", "CHANGELOG.md"]) {
170090
170790
  const source = join69(piPackageDir, entry);
170091
- if (existsSync51(source)) {
170791
+ if (existsSync52(source)) {
170092
170792
  symlinkSync3(source, join69(tmp, entry));
170093
170793
  }
170094
170794
  }
@@ -170107,8 +170807,8 @@ setInterval(() => {
170107
170807
  performance3.clearMarks();
170108
170808
  }, 3e4).unref();
170109
170809
  function loadEnvFile(path5) {
170110
- if (!existsSync51(path5)) return;
170111
- const contents = readFileSync23(path5, "utf-8");
170810
+ if (!existsSync52(path5)) return;
170811
+ const contents = readFileSync24(path5, "utf-8");
170112
170812
  for (const rawLine of contents.split(/\r?\n/)) {
170113
170813
  const line = rawLine.trim();
170114
170814
  if (!line || line.startsWith("#")) continue;
@@ -170419,8 +171119,36 @@ function getFlagValueNumber(args, flag) {
170419
171119
  const parsed = Number(value);
170420
171120
  return Number.isFinite(parsed) ? parsed : void 0;
170421
171121
  }
171122
+ function readOwnCliVersion() {
171123
+ let currentDir;
171124
+ try {
171125
+ currentDir = dirname29(fileURLToPath11(import.meta.url));
171126
+ } catch {
171127
+ return void 0;
171128
+ }
171129
+ for (let i = 0; i < 8; i += 1) {
171130
+ const pkgPath = resolve41(currentDir, "package.json");
171131
+ if (existsSync52(pkgPath)) {
171132
+ try {
171133
+ const parsed = JSON.parse(readFileSync24(pkgPath, "utf-8"));
171134
+ if (parsed.name === "@runfusion/fusion" && typeof parsed.version === "string") {
171135
+ return parsed.version;
171136
+ }
171137
+ } catch {
171138
+ }
171139
+ }
171140
+ const parentDir = resolve41(currentDir, "..");
171141
+ if (parentDir === currentDir) break;
171142
+ currentDir = parentDir;
171143
+ }
171144
+ return void 0;
171145
+ }
170422
171146
  async function main() {
170423
171147
  const { cleanedArgs: args, projectName } = extractGlobalProjectFlag(process.argv.slice(2));
171148
+ if (args.includes("--version") || args.includes("-v")) {
171149
+ console.log(readOwnCliVersion() ?? "unknown");
171150
+ process.exit(0);
171151
+ }
170424
171152
  if (args.includes("--help") || args.includes("-h")) {
170425
171153
  console.log(HELP);
170426
171154
  process.exit(0);