@runfusion/fusion 0.34.0 → 0.35.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 (49) hide show
  1. package/dist/bin.js +290 -84
  2. package/dist/client/.vite/manifest.json +56 -56
  3. package/dist/client/assets/{AgentDetailView-CzqwIIpv.js → AgentDetailView-CFX3jxfA.js} +1 -1
  4. package/dist/client/assets/{AgentPermissionPolicyEditor-2eoM2XQH.js → AgentPermissionPolicyEditor-4tnYHS0-.js} +1 -1
  5. package/dist/client/assets/{AgentsView-BrtAvhJl.js → AgentsView-DnNWfwiY.js} +3 -3
  6. package/dist/client/assets/ChatView-rwl2O-s0.js +6 -0
  7. package/dist/client/assets/{DevServerView-CF6FPLRb.js → DevServerView-C9fEzcFQ.js} +1 -1
  8. package/dist/client/assets/{DirectoryPicker-BpvHQxhu.js → DirectoryPicker-Cwyr0Sl4.js} +1 -1
  9. package/dist/client/assets/{DocumentsView-RMWZBJ-y.js → DocumentsView-gDWTMU2w.js} +1 -1
  10. package/dist/client/assets/{EvalsView-DtVxpc4T.js → EvalsView-Cw7D1x0W.js} +1 -1
  11. package/dist/client/assets/{ExperimentalAgentOnboardingModal-fzJmb-yG.js → ExperimentalAgentOnboardingModal-8yeOcqbX.js} +1 -1
  12. package/dist/client/assets/{GoalsView-BAchggxo.js → GoalsView-kRIhgAA6.js} +1 -1
  13. package/dist/client/assets/{InsightsView-B8892IbG.js → InsightsView-IHHikd5n.js} +1 -1
  14. package/dist/client/assets/{MemoryView-Cfp1WmAm.js → MemoryView-pii3HOba.js} +1 -1
  15. package/dist/client/assets/{NodesView-Dt26DSEQ.js → NodesView-CoDK14B3.js} +1 -1
  16. package/dist/client/assets/{PiExtensionsManager-xHU56SMh.js → PiExtensionsManager-vH7EJ5JD.js} +1 -1
  17. package/dist/client/assets/{PluginManager-37WUEOmp.js → PluginManager-PbkFQ0Nu.js} +1 -1
  18. package/dist/client/assets/{ResearchView-pu88M5xL.js → ResearchView-Dp4g_BWq.js} +1 -1
  19. package/dist/client/assets/{SecretsView-BT7ofJLN.js → SecretsView-Q8wES8_N.js} +1 -1
  20. package/dist/client/assets/SettingsModal-127YAB8c.js +31 -0
  21. package/dist/client/assets/{SettingsModal-DxYXsn08.js → SettingsModal-DdUztATB.js} +1 -1
  22. package/dist/client/assets/{SetupWizardModal-yWTk3Cac.js → SetupWizardModal-BSAFiQpJ.js} +1 -1
  23. package/dist/client/assets/{SkillsView-CWNfKNTs.js → SkillsView-Bj8KQQXB.js} +1 -1
  24. package/dist/client/assets/{StashRecoveryView-D0t4IIX-.js → StashRecoveryView-DvKN_b_k.js} +1 -1
  25. package/dist/client/assets/{TodoView-B4W1Lhy6.js → TodoView-C-cabt2D.js} +1 -1
  26. package/dist/client/assets/{dashboard-view-4OCJIthP.js → dashboard-view-DrHb8VOl.js} +1 -1
  27. package/dist/client/assets/{folder-open-BTdhwFQ5.js → folder-open-CYVKFKAx.js} +1 -1
  28. package/dist/client/assets/{index-k4s0JWir.css → index-Cuh_Pqv0.css} +1 -1
  29. package/dist/client/assets/{index-D4nQgFjo.js → index-Cze5qbME.js} +165 -165
  30. package/dist/client/assets/{upload-kESyjow_.js → upload-eQh-mH3-.js} +1 -1
  31. package/dist/client/assets/{users-DNXMrdcp.js → users-B5upejXg.js} +1 -1
  32. package/dist/client/index.html +2 -2
  33. package/dist/client/version.json +1 -1
  34. package/dist/droid-cli/package.json +1 -1
  35. package/dist/extension.js +241 -53
  36. package/dist/pi-claude-cli/package.json +1 -1
  37. package/dist/plugins/fusion-plugin-cli-printing-press/package.json +1 -1
  38. package/dist/plugins/fusion-plugin-cursor-runtime/package.json +1 -1
  39. package/dist/plugins/fusion-plugin-dependency-graph/package.json +1 -1
  40. package/dist/plugins/fusion-plugin-droid-runtime/package.json +1 -1
  41. package/dist/plugins/fusion-plugin-hermes-runtime/package.json +1 -1
  42. package/dist/plugins/fusion-plugin-openclaw-runtime/package.json +1 -1
  43. package/dist/plugins/fusion-plugin-paperclip-runtime/package.json +1 -1
  44. package/dist/plugins/fusion-plugin-reports/package.json +1 -1
  45. package/dist/plugins/fusion-plugin-roadmap/package.json +1 -1
  46. package/dist/plugins/fusion-plugin-whatsapp-chat/package.json +1 -1
  47. package/package.json +1 -1
  48. package/dist/client/assets/ChatView-BuIe4MhL.js +0 -6
  49. package/dist/client/assets/SettingsModal-Cz9MHNGg.js +0 -31
package/dist/bin.js CHANGED
@@ -2072,7 +2072,31 @@ Do NOT spend time on nits when no real issues exist.`
2072
2072
  ];
2073
2073
  DEFAULT_HEARTBEAT_PROCEDURE_PATH = ".fusion/HEARTBEAT.md";
2074
2074
  DASHBOARD_USER_ID = "dashboard";
2075
- DASHBOARD_USER_ALIASES = /* @__PURE__ */ new Set([DASHBOARD_USER_ID, "user:dashboard", "User: user:dashboard"]);
2075
+ DASHBOARD_USER_ALIASES = /* @__PURE__ */ new Set([DASHBOARD_USER_ID, "user", "user:dashboard", "User: user:dashboard"]);
2076
+ }
2077
+ });
2078
+
2079
+ // ../core/src/custom-provider-key.ts
2080
+ function slugifyProviderName(name) {
2081
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
2082
+ }
2083
+ function customProviderRegistryKey(provider, allProviders) {
2084
+ const base = slugifyProviderName(provider.name) || provider.id;
2085
+ let count = 0;
2086
+ for (const current of allProviders) {
2087
+ const currentBase = slugifyProviderName(current.name) || current.id;
2088
+ if (currentBase === base) {
2089
+ count += 1;
2090
+ }
2091
+ if (current.id === provider.id) {
2092
+ break;
2093
+ }
2094
+ }
2095
+ return count <= 1 ? base : `${base}-${count}`;
2096
+ }
2097
+ var init_custom_provider_key = __esm({
2098
+ "../core/src/custom-provider-key.ts"() {
2099
+ "use strict";
2076
2100
  }
2077
2101
  });
2078
2102
 
@@ -10499,7 +10523,7 @@ var init_message_store = __esm({
10499
10523
  }
10500
10524
  getParticipantIdsForLookup(ownerId, ownerType) {
10501
10525
  if (ownerType === "user" && ownerId === DASHBOARD_USER_ID) {
10502
- return [DASHBOARD_USER_ID, "user:dashboard", "User: user:dashboard"];
10526
+ return [DASHBOARD_USER_ID, "user", "user:dashboard", "User: user:dashboard"];
10503
10527
  }
10504
10528
  return [ownerId];
10505
10529
  }
@@ -25347,9 +25371,9 @@ var init_central_core = __esm({
25347
25371
  */
25348
25372
  async generateProjectName(projectPath) {
25349
25373
  try {
25350
- const { execFile: execFile21 } = await import("node:child_process");
25374
+ const { execFile: execFile22 } = await import("node:child_process");
25351
25375
  const { promisify: promisify57 } = await import("node:util");
25352
- const execFileAsync16 = promisify57(execFile21);
25376
+ const execFileAsync16 = promisify57(execFile22);
25353
25377
  const { stdout } = await execFileAsync16(
25354
25378
  "git",
25355
25379
  ["remote", "get-url", "origin"],
@@ -26054,9 +26078,9 @@ var init_migration = __esm({
26054
26078
  return basename5(projectPath);
26055
26079
  }
26056
26080
  try {
26057
- const { execFile: execFile21 } = await import("node:child_process");
26081
+ const { execFile: execFile22 } = await import("node:child_process");
26058
26082
  const { promisify: promisify57 } = await import("node:util");
26059
- const execFileAsync16 = promisify57(execFile21);
26083
+ const execFileAsync16 = promisify57(execFile22);
26060
26084
  const { stdout } = await execFileAsync16(
26061
26085
  "git",
26062
26086
  ["remote", "get-url", "origin"],
@@ -37805,9 +37829,9 @@ async function searchWithQmd(rootDir, options) {
37805
37829
  const command = "qmd";
37806
37830
  const limit = Math.max(1, Math.min(options.limit ?? 5, 20));
37807
37831
  try {
37808
- const { execFile: execFile21 } = await import("node:child_process");
37832
+ const { execFile: execFile22 } = await import("node:child_process");
37809
37833
  const { promisify: promisify57 } = await import("node:util");
37810
- const execFileAsync16 = promisify57(execFile21);
37834
+ const execFileAsync16 = promisify57(execFile22);
37811
37835
  await ensureQmdProjectMemoryCollection(rootDir, execFileAsync16);
37812
37836
  scheduleQmdProjectMemoryRefresh(rootDir);
37813
37837
  const args = buildQmdSearchArgs(rootDir, options);
@@ -37857,9 +37881,9 @@ ${stderr}`)) {
37857
37881
  return collectionName;
37858
37882
  }
37859
37883
  async function getDefaultExecFileAsync() {
37860
- const { execFile: execFile21 } = await import("node:child_process");
37884
+ const { execFile: execFile22 } = await import("node:child_process");
37861
37885
  const { promisify: promisify57 } = await import("node:util");
37862
- return promisify57(execFile21);
37886
+ return promisify57(execFile22);
37863
37887
  }
37864
37888
  async function refreshQmdProjectMemoryIndex(rootDir, options) {
37865
37889
  const key = resolve8(rootDir);
@@ -68624,7 +68648,7 @@ var init_chat_store = __esm({
68624
68648
  *
68625
68649
  * @param sessionId - Session ID
68626
68650
  * @param filter - Optional filter (limit, offset, before cursor)
68627
- * @returns Array of messages ordered by createdAt ASC
68651
+ * @returns Array of messages ordered by createdAt ASC (default) or DESC
68628
68652
  */
68629
68653
  getMessages(sessionId, filter2) {
68630
68654
  const whereClauses = ["sessionId = ?"];
@@ -68636,10 +68660,11 @@ var init_chat_store = __esm({
68636
68660
  const whereSql = whereClauses.join(" AND ");
68637
68661
  const limit = filter2?.limit ?? 100;
68638
68662
  const offset = filter2?.offset ?? 0;
68663
+ const order = filter2?.order === "desc" ? "DESC" : "ASC";
68639
68664
  const rows = this.db.prepare(`
68640
68665
  SELECT * FROM chat_messages
68641
68666
  WHERE ${whereSql}
68642
- ORDER BY createdAt ASC
68667
+ ORDER BY createdAt ${order}
68643
68668
  LIMIT ? OFFSET ?
68644
68669
  `).all(...params, limit, offset);
68645
68670
  return rows.map((row) => this.rowToMessage(row));
@@ -69672,6 +69697,7 @@ __export(src_exports, {
69672
69697
  createSecretCipher: () => createSecretCipher,
69673
69698
  createTaskMetadataSnapshot: () => createTaskMetadataSnapshot,
69674
69699
  currentBackupTimestamp: () => currentBackupTimestamp,
69700
+ customProviderRegistryKey: () => customProviderRegistryKey,
69675
69701
  dailyMemoryPath: () => dailyMemoryPath,
69676
69702
  detectDependencyCycle: () => detectDependencyCycle,
69677
69703
  detectFnBinary: () => detectFnBinary,
@@ -69997,6 +70023,7 @@ var init_src = __esm({
69997
70023
  "use strict";
69998
70024
  init_types();
69999
70025
  init_types();
70026
+ init_custom_provider_key();
70000
70027
  init_mock_provider_constants();
70001
70028
  init_worktrunk_settings();
70002
70029
  init_agent_memory_mode();
@@ -73270,7 +73297,7 @@ var init_workflow_step_tool_policy = __esm({
73270
73297
 
73271
73298
  // ../engine/src/pi.ts
73272
73299
  import { existsSync as existsSync25, readFileSync as readFileSync11 } from "node:fs";
73273
- import { exec as exec2 } from "node:child_process";
73300
+ import { exec as exec2, execFile as execFile3 } from "node:child_process";
73274
73301
  import { promisify as promisify3 } from "node:util";
73275
73302
  import { createRequire as createRequire3 } from "node:module";
73276
73303
  import { basename as basename9, dirname as dirname11, join as join31, relative as relative4, isAbsolute as isAbsolute8, resolve as resolve15 } from "node:path";
@@ -73293,6 +73320,60 @@ import {
73293
73320
  SessionManager,
73294
73321
  SettingsManager
73295
73322
  } from "@mariozechner/pi-coding-agent";
73323
+ function normalizeRtkRewriteOptions(options) {
73324
+ const modeEnv = process.env.FUSION_RTK_REWRITE?.toLowerCase();
73325
+ const envMode = modeEnv === "1" || modeEnv === "true" || modeEnv === "rewrite" ? "rewrite" : "off";
73326
+ const envTimeoutMs = Number.parseInt(process.env.FUSION_RTK_REWRITE_TIMEOUT_MS ?? "2000", 10);
73327
+ const requestedTimeoutMs = options?.timeoutMs ?? envTimeoutMs;
73328
+ return {
73329
+ mode: options?.mode ?? envMode,
73330
+ timeoutMs: Number.isFinite(requestedTimeoutMs) && requestedTimeoutMs > 0 ? requestedTimeoutMs : 2e3
73331
+ };
73332
+ }
73333
+ function resolveRtkRewriteOptions() {
73334
+ return normalizeRtkRewriteOptions();
73335
+ }
73336
+ function getRtkErrorCode(error) {
73337
+ if (!error) return 0;
73338
+ const rawCode = error.code;
73339
+ if (typeof rawCode === "number" || typeof rawCode === "string") return rawCode;
73340
+ return null;
73341
+ }
73342
+ function shouldWarnForRtkFailure(code) {
73343
+ if (typeof code === "number") return !RTK_EXPECTED_PASSTHROUGH_EXIT_CODES.has(code);
73344
+ if (typeof code === "string") return !RTK_EXPECTED_FAIL_OPEN_ERROR_CODES.has(code);
73345
+ return true;
73346
+ }
73347
+ function rewriteCommandWithRtk(command, options, signal) {
73348
+ if (signal?.aborted) {
73349
+ return Promise.resolve(null);
73350
+ }
73351
+ return new Promise((resolve64) => {
73352
+ execFile3(
73353
+ "rtk",
73354
+ ["rewrite", command],
73355
+ {
73356
+ timeout: options.timeoutMs,
73357
+ maxBuffer: RTK_REWRITE_MAX_BUFFER_BYTES,
73358
+ signal,
73359
+ windowsHide: true
73360
+ },
73361
+ (error, stdout, stderr) => {
73362
+ const code = getRtkErrorCode(error);
73363
+ if (typeof code !== "number" || !RTK_ACCEPTED_REWRITE_EXIT_CODES.has(code)) {
73364
+ if (shouldWarnForRtkFailure(code)) {
73365
+ const reason = stderr?.toString().trim() || (error instanceof Error ? error.message : `exit ${String(code)}`);
73366
+ piLog.warn(`[pi] rtk rewrite failed open: ${reason}`);
73367
+ }
73368
+ resolve64(null);
73369
+ return;
73370
+ }
73371
+ const rewritten = stdout.toString().trim();
73372
+ resolve64(rewritten && rewritten !== command ? rewritten : null);
73373
+ }
73374
+ );
73375
+ });
73376
+ }
73296
73377
  function setHostExtensionPaths(paths) {
73297
73378
  hostExtensionPaths = [...paths];
73298
73379
  }
@@ -74193,6 +74274,36 @@ function wrapToolsWithBoundary(tools, worktreePath, projectRoot) {
74193
74274
  };
74194
74275
  });
74195
74276
  }
74277
+ function wrapToolsWithRtkRewrite(tools, options = resolveRtkRewriteOptions()) {
74278
+ const resolvedOptions = normalizeRtkRewriteOptions(options);
74279
+ if (resolvedOptions.mode !== "rewrite") {
74280
+ return tools;
74281
+ }
74282
+ return tools.map((tool) => {
74283
+ if (tool.name !== "bash") {
74284
+ return tool;
74285
+ }
74286
+ const originalExecute = tool.execute;
74287
+ return {
74288
+ ...tool,
74289
+ execute: async (...args) => {
74290
+ const params = args[1];
74291
+ const command = params?.command;
74292
+ if (typeof command !== "string" || !command.trim()) {
74293
+ return originalExecute(...args);
74294
+ }
74295
+ const signal = args[2];
74296
+ const rewrittenCommand = await rewriteCommandWithRtk(command, resolvedOptions, signal);
74297
+ if (!rewrittenCommand) {
74298
+ return originalExecute(...args);
74299
+ }
74300
+ const rewrittenArgs = [...args];
74301
+ rewrittenArgs[1] = { ...params ?? {}, command: rewrittenCommand };
74302
+ return originalExecute(...rewrittenArgs);
74303
+ }
74304
+ };
74305
+ });
74306
+ }
74196
74307
  function wrapToolsWithPermanentAgentGating(tools, gating) {
74197
74308
  if (!gating) {
74198
74309
  return tools;
@@ -74328,11 +74439,13 @@ async function createFnAgent2(options) {
74328
74439
  const modelRegistry = ModelRegistry.create(authStorage, getModelRegistryModelsPath());
74329
74440
  const resolvedProjectRoot = getProjectRootFromWorktree(options.cwd) ?? resolvePiExtensionProjectRoot(options.cwd);
74330
74441
  await registerExtensionProviders(resolvedProjectRoot, modelRegistry);
74331
- for (const provider of readCustomProviders()) {
74442
+ const customProviders = readCustomProviders();
74443
+ for (const provider of customProviders) {
74332
74444
  try {
74333
- modelRegistry.registerProvider(provider.id, {
74445
+ const registryKey2 = customProviderRegistryKey(provider, customProviders);
74446
+ modelRegistry.registerProvider(registryKey2, {
74334
74447
  baseUrl: provider.baseUrl,
74335
- api: provider.apiType === "anthropic-compatible" ? "anthropic" : "openai-completions",
74448
+ api: provider.apiType === "anthropic-compatible" ? "anthropic" : provider.apiType === "openai-responses" ? "openai-responses" : "openai-completions",
74336
74449
  apiKey: provider.apiKey,
74337
74450
  models: (provider.models ?? []).map((model) => ({
74338
74451
  id: model.id,
@@ -74349,10 +74462,11 @@ async function createFnAgent2(options) {
74349
74462
  maxTokens: 16384
74350
74463
  }))
74351
74464
  });
74352
- piLog.log(`Registered custom provider ${provider.id}`);
74465
+ piLog.log(`Registered custom provider "${provider.name}" (key=${registryKey2}, id=${provider.id})`);
74353
74466
  } catch (error) {
74354
74467
  const message = error instanceof Error ? error.message : String(error);
74355
- piLog.warn(`Failed to register custom provider ${provider.id}: ${message}`);
74468
+ const registryKey2 = customProviderRegistryKey(provider, customProviders);
74469
+ piLog.warn(`Failed to register custom provider "${provider.name}" (key=${registryKey2}, id=${provider.id}): ${message}`);
74356
74470
  }
74357
74471
  }
74358
74472
  modelRegistry.refresh();
@@ -74471,8 +74585,9 @@ async function createFnAgent2(options) {
74471
74585
  ...tools,
74472
74586
  ...readonlyFilteredCustomTools.allowed
74473
74587
  ];
74588
+ const toolsWithRtkRewrite = wrapToolsWithRtkRewrite(toolChainStart);
74474
74589
  const toolsWithPermanentGating = wrapToolsWithPermanentAgentGating(
74475
- toolChainStart,
74590
+ toolsWithRtkRewrite,
74476
74591
  options.permanentAgentGating
74477
74592
  );
74478
74593
  const toolsWithActionGate = wrapToolsWithActionGate(
@@ -74739,7 +74854,7 @@ async function createFnAgent2(options) {
74739
74854
  });
74740
74855
  return { session: promptableSession, sessionFile: promptableSession.sessionFile };
74741
74856
  }
74742
- var execAsync, hostExtensionPaths, FN_MEMORY_APPEND_TOOL_NAME, FUSION_SHUTDOWN_WRAP_FLAG, promptWithFallbackInFlight, COMPACTION_FALLBACK_INSTRUCTIONS, MAX_COMPACTED_PROMPT_MEMORY_CHARS, MAX_COMPACTED_SUBTASK_GUIDANCE_CHARS, MAX_COMPACTED_ATTACHMENTS_CHARS, MAX_COMPACTED_EXISTING_SPEC_CHARS, MAX_COMPACTED_TASK_PROMPT_CHARS, MAX_COMPACTED_USER_COMMENTS_CHARS, GATE_BYPASS_TOOL_NAMES;
74857
+ var execAsync, RTK_ACCEPTED_REWRITE_EXIT_CODES, RTK_EXPECTED_PASSTHROUGH_EXIT_CODES, RTK_EXPECTED_FAIL_OPEN_ERROR_CODES, RTK_REWRITE_MAX_BUFFER_BYTES, hostExtensionPaths, FN_MEMORY_APPEND_TOOL_NAME, FUSION_SHUTDOWN_WRAP_FLAG, promptWithFallbackInFlight, COMPACTION_FALLBACK_INSTRUCTIONS, MAX_COMPACTED_PROMPT_MEMORY_CHARS, MAX_COMPACTED_SUBTASK_GUIDANCE_CHARS, MAX_COMPACTED_ATTACHMENTS_CHARS, MAX_COMPACTED_EXISTING_SPEC_CHARS, MAX_COMPACTED_TASK_PROMPT_CHARS, MAX_COMPACTED_USER_COMMENTS_CHARS, GATE_BYPASS_TOOL_NAMES;
74743
74858
  var init_pi = __esm({
74744
74859
  "../engine/src/pi.ts"() {
74745
74860
  "use strict";
@@ -74753,6 +74868,10 @@ var init_pi = __esm({
74753
74868
  init_permanent_agent_gating();
74754
74869
  init_workflow_step_tool_policy();
74755
74870
  execAsync = promisify3(exec2);
74871
+ RTK_ACCEPTED_REWRITE_EXIT_CODES = /* @__PURE__ */ new Set([0, 3]);
74872
+ RTK_EXPECTED_PASSTHROUGH_EXIT_CODES = /* @__PURE__ */ new Set([1, 2]);
74873
+ RTK_EXPECTED_FAIL_OPEN_ERROR_CODES = /* @__PURE__ */ new Set(["ABORT_ERR", "ENOENT", "ETIMEDOUT"]);
74874
+ RTK_REWRITE_MAX_BUFFER_BYTES = 64 * 1024;
74756
74875
  hostExtensionPaths = [];
74757
74876
  FN_MEMORY_APPEND_TOOL_NAME = "fn_memory_append";
74758
74877
  FUSION_SHUTDOWN_WRAP_FLAG = "__fusionSessionShutdownDisposeWrapped";
@@ -76356,9 +76475,9 @@ async function refreshAgentMemoryQmdIndex(rootDir, agentMemory) {
76356
76475
  return;
76357
76476
  }
76358
76477
  const promise = (async () => {
76359
- const { execFile: execFile21 } = await import("node:child_process");
76478
+ const { execFile: execFile22 } = await import("node:child_process");
76360
76479
  const { promisify: promisify57 } = await import("node:util");
76361
- const execFileAsync16 = promisify57(execFile21);
76480
+ const execFileAsync16 = promisify57(execFile22);
76362
76481
  try {
76363
76482
  await execFileAsync16("qmd", buildQmdAgentMemoryCollectionAddArgs(rootDir, agentMemory.agentId), {
76364
76483
  cwd: rootDir,
@@ -76429,9 +76548,9 @@ async function searchAgentMemoryWithQmd(rootDir, agentMemory, query, limit) {
76429
76548
  }
76430
76549
  try {
76431
76550
  await refreshAgentMemoryQmdIndex(rootDir, agentMemory);
76432
- const { execFile: execFile21 } = await import("node:child_process");
76551
+ const { execFile: execFile22 } = await import("node:child_process");
76433
76552
  const { promisify: promisify57 } = await import("node:util");
76434
- const execFileAsync16 = promisify57(execFile21);
76553
+ const execFileAsync16 = promisify57(execFile22);
76435
76554
  const { stdout } = await execFileAsync16("qmd", buildQmdAgentMemorySearchArgs(rootDir, agentMemory.agentId, query, limit), {
76436
76555
  cwd: rootDir,
76437
76556
  timeout: 4e3,
@@ -80487,6 +80606,69 @@ var init_oauth_expiry_monitor = __esm({
80487
80606
  }
80488
80607
  });
80489
80608
 
80609
+ // ../engine/src/notification/oauth-validity-logger.ts
80610
+ var DEFAULT_INTERVAL_MS2, OAuthValidityLogger;
80611
+ var init_oauth_validity_logger = __esm({
80612
+ "../engine/src/notification/oauth-validity-logger.ts"() {
80613
+ "use strict";
80614
+ init_logger2();
80615
+ DEFAULT_INTERVAL_MS2 = 24 * 60 * 60 * 1e3;
80616
+ OAuthValidityLogger = class {
80617
+ constructor(opts) {
80618
+ this.opts = opts;
80619
+ this.intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS2;
80620
+ this.clock = opts.clock ?? Date.now;
80621
+ this.logger = opts.logger ?? ((message, meta) => schedulerLog.warn(message, meta));
80622
+ }
80623
+ intervalMs;
80624
+ clock;
80625
+ logger;
80626
+ timer = null;
80627
+ async start() {
80628
+ if (this.timer) {
80629
+ return;
80630
+ }
80631
+ await this.check();
80632
+ this.timer = setInterval(() => {
80633
+ void this.check();
80634
+ }, this.intervalMs);
80635
+ this.timer.unref?.();
80636
+ }
80637
+ stop() {
80638
+ if (!this.timer) {
80639
+ return;
80640
+ }
80641
+ clearInterval(this.timer);
80642
+ this.timer = null;
80643
+ }
80644
+ async check() {
80645
+ this.opts.authStorage.reload?.();
80646
+ const providers = this.opts.authStorage.getOAuthProviders?.() ?? [];
80647
+ const now = this.clock();
80648
+ for (const provider of providers) {
80649
+ try {
80650
+ const credential = this.opts.authStorage.get?.(provider.id);
80651
+ if (credential?.type !== "oauth" || typeof credential.expires !== "number") {
80652
+ continue;
80653
+ }
80654
+ if (credential.expires > now) {
80655
+ continue;
80656
+ }
80657
+ this.logger("oauth credential expired \u2014 provider re-login required", {
80658
+ providerId: provider.id,
80659
+ providerName: provider.name,
80660
+ expiresAt: new Date(credential.expires).toISOString()
80661
+ });
80662
+ } catch (error) {
80663
+ const message = error instanceof Error ? error.message : String(error);
80664
+ schedulerLog.warn(`OAuth validity logger failed for provider=${provider.id}: ${message}`);
80665
+ }
80666
+ }
80667
+ }
80668
+ };
80669
+ }
80670
+ });
80671
+
80490
80672
  // ../engine/src/notification/index.ts
80491
80673
  var init_notification = __esm({
80492
80674
  "../engine/src/notification/index.ts"() {
@@ -80495,6 +80677,7 @@ var init_notification = __esm({
80495
80677
  init_webhook_provider();
80496
80678
  init_notification_service();
80497
80679
  init_oauth_expiry_monitor();
80680
+ init_oauth_validity_logger();
80498
80681
  }
80499
80682
  });
80500
80683
 
@@ -84310,7 +84493,7 @@ ${getErrorStderr(error) ?? ""}`;
84310
84493
  import { createHash as createHash9 } from "node:crypto";
84311
84494
  import { promises as fs5 } from "node:fs";
84312
84495
  import path2 from "node:path";
84313
- import { execFile as execFile3 } from "node:child_process";
84496
+ import { execFile as execFile4 } from "node:child_process";
84314
84497
  function isValidFilename(filename) {
84315
84498
  return !!filename && !filename.includes("/") && !filename.includes("\\") && !filename.includes("..") && !filename.includes("\0") && filename !== FINGERPRINT_FILE;
84316
84499
  }
@@ -84371,7 +84554,7 @@ async function writeSecretsEnvFile(opts) {
84371
84554
  } catch {
84372
84555
  }
84373
84556
  if (cfg?.requireGitignored !== false) {
84374
- const check = await checkIgnored(opts.execFileImpl ?? execFile3, opts.worktreePath, filename);
84557
+ const check = await checkIgnored(opts.execFileImpl ?? execFile4, opts.worktreePath, filename);
84375
84558
  if (!check.ignored) {
84376
84559
  await opts.audit?.filesystem({ type: "secret:env-write-skipped", target: opts.taskId, metadata: { filename, reason: "not-gitignored", overwritePolicy, checkIgnoreError: check.error } });
84377
84560
  return { outcome: "skipped", filename, reason: "not-gitignored" };
@@ -89319,7 +89502,7 @@ var init_session_token_usage = __esm({
89319
89502
  });
89320
89503
 
89321
89504
  // ../engine/src/merger-squash-audit.ts
89322
- import { execFile as execFile5 } from "node:child_process";
89505
+ import { execFile as execFile6 } from "node:child_process";
89323
89506
  import { promisify as promisify24 } from "node:util";
89324
89507
  async function auditSquashMerge(input) {
89325
89508
  const normalizedLookback = normalizeMergeOverlapLookback(input.lookback);
@@ -89475,14 +89658,14 @@ var execFileAsync, MERGER_MAIN_OVERLAP_LOOKBACK_COMMITS, GIT_OUTPUT_MAX_BUFFER;
89475
89658
  var init_merger_squash_audit = __esm({
89476
89659
  "../engine/src/merger-squash-audit.ts"() {
89477
89660
  "use strict";
89478
- execFileAsync = promisify24(execFile5);
89661
+ execFileAsync = promisify24(execFile6);
89479
89662
  MERGER_MAIN_OVERLAP_LOOKBACK_COMMITS = 30;
89480
89663
  GIT_OUTPUT_MAX_BUFFER = 10 * 1024 * 1024;
89481
89664
  }
89482
89665
  });
89483
89666
 
89484
89667
  // ../engine/src/merger-overlap-guard.ts
89485
- import { execFile as execFile6 } from "node:child_process";
89668
+ import { execFile as execFile7 } from "node:child_process";
89486
89669
  import { promisify as promisify25 } from "node:util";
89487
89670
  async function getBranchTouchedFiles({
89488
89671
  rootDir,
@@ -89608,13 +89791,13 @@ var init_merger_overlap_guard = __esm({
89608
89791
  "use strict";
89609
89792
  init_logger2();
89610
89793
  init_merger_squash_audit();
89611
- execFileAsync2 = promisify25(execFile6);
89794
+ execFileAsync2 = promisify25(execFile7);
89612
89795
  GIT_OUTPUT_MAX_BUFFER2 = 10 * 1024 * 1024;
89613
89796
  }
89614
89797
  });
89615
89798
 
89616
89799
  // ../engine/src/merger-diff-volume-gate.ts
89617
- import { execFile as execFile7 } from "node:child_process";
89800
+ import { execFile as execFile8 } from "node:child_process";
89618
89801
  import { promisify as promisify26 } from "node:util";
89619
89802
  function buildMessage(findings) {
89620
89803
  const details = findings.map((finding) => `${finding.file} (branch_net=${finding.branchNet}, staged=${finding.staged}, ratio=${finding.ratio.toFixed(3)})`).join(", ");
@@ -89676,7 +89859,7 @@ var init_merger_diff_volume_gate = __esm({
89676
89859
  "../engine/src/merger-diff-volume-gate.ts"() {
89677
89860
  "use strict";
89678
89861
  init_merger();
89679
- execFileAsync3 = promisify26(execFile7);
89862
+ execFileAsync3 = promisify26(execFile8);
89680
89863
  DiffVolumeRegressionError = class extends Error {
89681
89864
  constructor(findings) {
89682
89865
  super(buildMessage(findings));
@@ -90337,7 +90520,7 @@ var init_mesh_lease_manager = __esm({
90337
90520
 
90338
90521
  // ../engine/src/merger-integration-worktree.ts
90339
90522
  import { createHash as createHash10 } from "node:crypto";
90340
- import { exec as exec25, execFile as execFile8 } from "node:child_process";
90523
+ import { exec as exec25, execFile as execFile9 } from "node:child_process";
90341
90524
  import { promisify as promisify29 } from "node:util";
90342
90525
  function quoteAutostashArg(value) {
90343
90526
  return `"${value.replace(/(["\\$`])/g, "\\$1")}"`;
@@ -90816,7 +90999,7 @@ var init_merger_integration_worktree = __esm({
90816
90999
  init_worktree_pool();
90817
91000
  init_worktree_names();
90818
91001
  execAsync23 = promisify29(exec25);
90819
- execFileAsync4 = promisify29(execFile8);
91002
+ execFileAsync4 = promisify29(execFile9);
90820
91003
  MERGE_HANDOFF_WORKER_ID = "merger-reuse-handoff";
90821
91004
  MergeHandoffRefusedError = class extends Error {
90822
91005
  reason;
@@ -91529,7 +91712,7 @@ var init_worktree_acquisition = __esm({
91529
91712
  });
91530
91713
 
91531
91714
  // ../engine/src/merger-ref-update-advance.ts
91532
- import { execFile as execFile9 } from "node:child_process";
91715
+ import { execFile as execFile10 } from "node:child_process";
91533
91716
  import { promisify as promisify31 } from "node:util";
91534
91717
  async function runGit3(args, cwd) {
91535
91718
  return await execFileAsync5("git", args, {
@@ -91673,7 +91856,7 @@ var execFileAsync5, testHooks, IntegrationBranchConcurrentAdvanceError;
91673
91856
  var init_merger_ref_update_advance = __esm({
91674
91857
  "../engine/src/merger-ref-update-advance.ts"() {
91675
91858
  "use strict";
91676
- execFileAsync5 = promisify31(execFile9);
91859
+ execFileAsync5 = promisify31(execFile10);
91677
91860
  testHooks = {
91678
91861
  runGit: runGit3
91679
91862
  };
@@ -91700,7 +91883,7 @@ var init_merger_ref_update_advance = __esm({
91700
91883
  });
91701
91884
 
91702
91885
  // ../engine/src/worktree-ref-sync.ts
91703
- import { execFile as execFile10, spawn as spawn5 } from "node:child_process";
91886
+ import { execFile as execFile11, spawn as spawn5 } from "node:child_process";
91704
91887
  import { promisify as promisify32 } from "node:util";
91705
91888
  import { copyFileSync, existsSync as existsSync36, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync2, readFileSync as readFileSync12, rmSync as rmSync3, writeFileSync as writeFileSync2 } from "node:fs";
91706
91889
  import { dirname as dirname17, join as join40 } from "node:path";
@@ -91944,7 +92127,7 @@ var execFileAsync6;
91944
92127
  var init_worktree_ref_sync = __esm({
91945
92128
  "../engine/src/worktree-ref-sync.ts"() {
91946
92129
  "use strict";
91947
- execFileAsync6 = promisify32(execFile10);
92130
+ execFileAsync6 = promisify32(execFile11);
91948
92131
  }
91949
92132
  });
91950
92133
 
@@ -92215,7 +92398,7 @@ __export(merger_exports, {
92215
92398
  tryFastForwardFromOrigin: () => tryFastForwardFromOrigin,
92216
92399
  validateDiffScope: () => validateDiffScope
92217
92400
  });
92218
- import { execSync as execSync4, exec as exec28, execFile as execFile11 } from "node:child_process";
92401
+ import { execSync as execSync4, exec as exec28, execFile as execFile12 } from "node:child_process";
92219
92402
  import { promisify as promisify34 } from "node:util";
92220
92403
  import { existsSync as existsSync37, readFileSync as readFileSync13, readdirSync as readdirSync5, writeFileSync as writeFileSync3, unlinkSync, renameSync as renameSync2 } from "node:fs";
92221
92404
  import { createHash as createHash11 } from "node:crypto";
@@ -100655,7 +100838,7 @@ var init_merger = __esm({
100655
100838
  init_merger_diff_volume_gate();
100656
100839
  init_merger_ref_update_advance();
100657
100840
  execAsync26 = promisify34(exec28);
100658
- execFileAsync7 = promisify34(execFile11);
100841
+ execFileAsync7 = promisify34(execFile12);
100659
100842
  LOCKFILE_PATTERNS = [
100660
100843
  "package-lock.json",
100661
100844
  "pnpm-lock.yaml",
@@ -109703,7 +109886,7 @@ Take a completely different approach to writing this specification. Do NOT repea
109703
109886
  });
109704
109887
 
109705
109888
  // ../engine/src/merger-orphan-rehome.ts
109706
- import { execFile as execFile12 } from "node:child_process";
109889
+ import { execFile as execFile13 } from "node:child_process";
109707
109890
  import { promisify as promisify37 } from "node:util";
109708
109891
  async function runGit5(args, cwd) {
109709
109892
  const { stdout } = await execFileAsync8("git", args, {
@@ -109809,7 +109992,7 @@ var init_merger_orphan_rehome = __esm({
109809
109992
  "../engine/src/merger-orphan-rehome.ts"() {
109810
109993
  "use strict";
109811
109994
  init_merger_ref_update_advance();
109812
- execFileAsync8 = promisify37(execFile12);
109995
+ execFileAsync8 = promisify37(execFile13);
109813
109996
  }
109814
109997
  });
109815
109998
 
@@ -122716,7 +122899,7 @@ ${taskContext}` : ""}`;
122716
122899
  });
122717
122900
 
122718
122901
  // ../engine/src/smart-pull.ts
122719
- import { execFile as execFile13 } from "node:child_process";
122902
+ import { execFile as execFile14 } from "node:child_process";
122720
122903
  import { promisify as promisify41 } from "node:util";
122721
122904
  async function runGit6(args, cwd, timeoutMs) {
122722
122905
  const result = await execFileAsync9("git", args, {
@@ -122874,7 +123057,7 @@ var execFileAsync9;
122874
123057
  var init_smart_pull = __esm({
122875
123058
  "../engine/src/smart-pull.ts"() {
122876
123059
  "use strict";
122877
- execFileAsync9 = promisify41(execFile13);
123060
+ execFileAsync9 = promisify41(execFile14);
122878
123061
  }
122879
123062
  });
122880
123063
 
@@ -135154,7 +135337,7 @@ var init_provider_adapters = __esm({
135154
135337
 
135155
135338
  // ../engine/src/remote-access/tunnel-process-manager.ts
135156
135339
  import { EventEmitter as EventEmitter25 } from "node:events";
135157
- import { exec as exec36, execFile as execFile14, spawn as spawn8 } from "node:child_process";
135340
+ import { exec as exec36, execFile as execFile15, spawn as spawn8 } from "node:child_process";
135158
135341
  import { promisify as promisify43 } from "node:util";
135159
135342
  function nowIso2() {
135160
135343
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -135204,7 +135387,7 @@ var init_tunnel_process_manager = __esm({
135204
135387
  init_provider_adapters();
135205
135388
  DEFAULT_MAX_LOG_ENTRIES = 400;
135206
135389
  DEFAULT_STOP_TIMEOUT_MS2 = 5e3;
135207
- execFileAsync10 = promisify43(execFile14);
135390
+ execFileAsync10 = promisify43(execFile15);
135208
135391
  execAsync32 = promisify43(exec36);
135209
135392
  LineBuffer = class {
135210
135393
  pending = "";
@@ -135606,7 +135789,7 @@ var init_tunnel_process_manager = __esm({
135606
135789
  });
135607
135790
 
135608
135791
  // ../engine/src/project-engine.ts
135609
- import { execFile as execFile15 } from "node:child_process";
135792
+ import { execFile as execFile16 } from "node:child_process";
135610
135793
  import { promisify as promisify44 } from "node:util";
135611
135794
  function formatErrorDetails(error) {
135612
135795
  if (error instanceof Error) {
@@ -135654,7 +135837,7 @@ var init_project_engine = __esm({
135654
135837
  init_run_audit();
135655
135838
  init_verification_followup_dedup();
135656
135839
  init_tunnel_process_manager();
135657
- execFileAsync11 = promisify44(execFile15);
135840
+ execFileAsync11 = promisify44(execFile16);
135658
135841
  MERGE_HANDOFF_GRACE_MS = 300;
135659
135842
  isRemoteActive = (ra) => ra?.activeProvider != null && (ra.providers[ra.activeProvider]?.enabled ?? false);
135660
135843
  ProjectEngine = class _ProjectEngine {
@@ -135686,6 +135869,7 @@ var init_project_engine = __esm({
135686
135869
  notifier;
135687
135870
  notificationService;
135688
135871
  oauthExpiryMonitor;
135872
+ oauthValidityLogger;
135689
135873
  gridlockDetector;
135690
135874
  cronRunner;
135691
135875
  automationStore;
@@ -135799,11 +135983,14 @@ var init_project_engine = __esm({
135799
135983
  agentNameResolver
135800
135984
  });
135801
135985
  await this.notificationService.start();
135986
+ const authStorage = createFusionAuthStorage();
135802
135987
  this.oauthExpiryMonitor = new OAuthExpiryMonitor({
135803
- authStorage: createFusionAuthStorage(),
135988
+ authStorage,
135804
135989
  notificationService: this.notificationService
135805
135990
  });
135806
135991
  await this.oauthExpiryMonitor.start();
135992
+ this.oauthValidityLogger = new OAuthValidityLogger({ authStorage });
135993
+ await this.oauthValidityLogger.start();
135807
135994
  this.notifier = new NtfyNotifier(
135808
135995
  store,
135809
135996
  {
@@ -135987,6 +136174,7 @@ ${detail}`
135987
136174
  } catch {
135988
136175
  }
135989
136176
  this.oauthExpiryMonitor?.stop();
136177
+ this.oauthValidityLogger?.stop();
135990
136178
  this.notificationService?.stop();
135991
136179
  this.notifier?.stop();
135992
136180
  this.gridlockDetector?.stop();
@@ -151571,7 +151759,7 @@ var init_pr_metadata_generator = __esm({
151571
151759
  });
151572
151760
 
151573
151761
  // ../dashboard/src/routes/resolve-diff-base.ts
151574
- import { execFile as execFile16 } from "node:child_process";
151762
+ import { execFile as execFile17 } from "node:child_process";
151575
151763
  import { promisify as promisify47 } from "node:util";
151576
151764
  async function runGitCommand(args, cwd, timeout2 = 1e4) {
151577
151765
  const result = await execFileAsync12("git", args, {
@@ -151652,7 +151840,7 @@ var execFileAsync12;
151652
151840
  var init_resolve_diff_base = __esm({
151653
151841
  "../dashboard/src/routes/resolve-diff-base.ts"() {
151654
151842
  "use strict";
151655
- execFileAsync12 = promisify47(execFile16);
151843
+ execFileAsync12 = promisify47(execFile17);
151656
151844
  }
151657
151845
  });
151658
151846
 
@@ -161275,7 +161463,7 @@ function registerChatRoutes(ctx, deps) {
161275
161463
  if (!session) {
161276
161464
  throw notFound(`Chat session ${sessionId} not found`);
161277
161465
  }
161278
- const { limit: limitStr, offset: offsetStr, before } = req.query;
161466
+ const { limit: limitStr, offset: offsetStr, before, order } = req.query;
161279
161467
  const limit = limitStr !== void 0 ? parseInt(String(limitStr), 10) : 50;
161280
161468
  const offset = offsetStr !== void 0 ? parseInt(String(offsetStr), 10) : 0;
161281
161469
  if (!Number.isFinite(limit) || limit < 1) {
@@ -161284,11 +161472,15 @@ function registerChatRoutes(ctx, deps) {
161284
161472
  if (!Number.isFinite(offset) || offset < 0) {
161285
161473
  throw badRequest("offset must be a non-negative integer");
161286
161474
  }
161475
+ if (order !== void 0 && order !== "asc" && order !== "desc") {
161476
+ throw badRequest('order must be "asc" or "desc"');
161477
+ }
161287
161478
  const effectiveLimit = Math.min(limit, 200);
161288
161479
  const messages = chatStore.getMessages(sessionId, {
161289
161480
  limit: effectiveLimit,
161290
161481
  offset,
161291
- ...before && { before }
161482
+ ...before && { before },
161483
+ ...order === "desc" || order === "asc" ? { order } : {}
161292
161484
  });
161293
161485
  res.json({ messages });
161294
161486
  } catch (err) {
@@ -166710,7 +166902,7 @@ var init_remote_auth = __esm({
166710
166902
  // ../dashboard/src/routes/register-settings-memory-routes.ts
166711
166903
  import crypto from "node:crypto";
166712
166904
  import { createReadStream as createReadStream4 } from "node:fs";
166713
- import { execFile as execFile17 } from "node:child_process";
166905
+ import { execFile as execFile18 } from "node:child_process";
166714
166906
  import { homedir as homedir9 } from "node:os";
166715
166907
  import { mkdir as mkdir18 } from "node:fs/promises";
166716
166908
  import { promisify as promisify49 } from "node:util";
@@ -166776,7 +166968,7 @@ function validateCloudflaredManifest(input) {
166776
166968
  function registerSettingsMemoryRoutes(ctx, deps) {
166777
166969
  const { router, options, store, runtimeLogger, getProjectContext: getProjectContext3, rethrowAsApiError: rethrowAsApiError9 } = ctx;
166778
166970
  const { githubToken, validateModelPresets: validateModelPresets2, sanitizeOverlapIgnorePaths: sanitizeOverlapIgnorePaths2, discoverDashboardPiExtensions: discoverDashboardPiExtensions2 } = deps;
166779
- const execFileAsync16 = promisify49(execFile17);
166971
+ const execFileAsync16 = promisify49(execFile18);
166780
166972
  async function queryTailscaleFunnelUrl(targetPort) {
166781
166973
  try {
166782
166974
  const { stdout } = await execFileAsync16("tailscale", ["status", "--json"], { timeout: 3e3 });
@@ -197178,13 +197370,13 @@ var init_register_agents_projects_nodes = __esm({
197178
197370
  });
197179
197371
 
197180
197372
  // ../dashboard/src/exec-file.ts
197181
- import { execFile as execFile18 } from "node:child_process";
197373
+ import { execFile as execFile19 } from "node:child_process";
197182
197374
  import { promisify as promisify50 } from "node:util";
197183
197375
  var execFileAsync13;
197184
197376
  var init_exec_file = __esm({
197185
197377
  "../dashboard/src/exec-file.ts"() {
197186
197378
  "use strict";
197187
- execFileAsync13 = promisify50(execFile18);
197379
+ execFileAsync13 = promisify50(execFile19);
197188
197380
  }
197189
197381
  });
197190
197382
 
@@ -209399,8 +209591,8 @@ function assertNonEmptyString(value, fieldName) {
209399
209591
  return value.trim();
209400
209592
  }
209401
209593
  function assertApiType(value) {
209402
- if (value !== "openai-compatible" && value !== "anthropic-compatible" && value !== "google-generative-ai") {
209403
- throw badRequest("apiType must be 'openai-compatible', 'anthropic-compatible', or 'google-generative-ai'");
209594
+ if (value !== "openai-compatible" && value !== "anthropic-compatible" && value !== "google-generative-ai" && value !== "openai-responses") {
209595
+ throw badRequest("apiType must be 'openai-compatible', 'anthropic-compatible', 'google-generative-ai', or 'openai-responses'");
209404
209596
  }
209405
209597
  return value;
209406
209598
  }
@@ -209538,7 +209730,7 @@ async function probeProviderModels(baseUrl, apiKey, apiType) {
209538
209730
  "Content-Type": "application/json",
209539
209731
  "User-Agent": "Fusion/1.0"
209540
209732
  };
209541
- if (apiType === "openai-compatible") {
209733
+ if (apiType === "openai-compatible" || apiType === "openai-responses") {
209542
209734
  const pathname = url.pathname.replace(/\/+$/, "");
209543
209735
  const modelsPath = pathname ? pathname + "/models" : "/models";
209544
209736
  modelsUrl = new URL(modelsPath, url.origin).toString();
@@ -209755,9 +209947,9 @@ var init_register_custom_provider_routes = __esm({
209755
209947
  const baseUrl = assertBaseUrl(body.baseUrl);
209756
209948
  const apiKey = typeof body.apiKey === "string" && body.apiKey.trim().length > 0 ? body.apiKey.trim() : void 0;
209757
209949
  const rawApiType = body.apiType;
209758
- if (rawApiType !== "openai-compatible" && rawApiType !== "anthropic-compatible" && rawApiType !== "google-generative-ai") {
209950
+ if (rawApiType !== "openai-compatible" && rawApiType !== "anthropic-compatible" && rawApiType !== "google-generative-ai" && rawApiType !== "openai-responses") {
209759
209951
  throw badRequest(
209760
- "apiType must be 'openai-compatible', 'anthropic-compatible', or 'google-generative-ai'"
209952
+ "apiType must be 'openai-compatible', 'anthropic-compatible', 'google-generative-ai', or 'openai-responses'"
209761
209953
  );
209762
209954
  }
209763
209955
  const apiType = rawApiType;
@@ -212748,14 +212940,19 @@ var init_register_auth_routes = __esm({
212748
212940
  const storage = getAuthStorage();
212749
212941
  storage.reload();
212750
212942
  const oauthProviders = storage.getOAuthProviders();
212751
- const providers = oauthProviders.map((p2) => ({
212752
- id: p2.id,
212753
- name: p2.name,
212754
- authenticated: storage.hasAuth(p2.id) && !isExpiredOauthCredential(p2.id, storage),
212755
- type: "oauth",
212756
- loginInProgress: loginInProgress.has(p2.id),
212757
- requiresManualCode: getManualCodeConfig(p2.id, origin) !== void 0 || void 0
212758
- }));
212943
+ const providers = oauthProviders.map((p2) => {
212944
+ const hasAuth = storage.hasAuth(p2.id);
212945
+ const expired = hasAuth && isExpiredOauthCredential(p2.id, storage);
212946
+ return {
212947
+ id: p2.id,
212948
+ name: p2.name,
212949
+ authenticated: hasAuth && !expired,
212950
+ type: "oauth",
212951
+ expired,
212952
+ loginInProgress: loginInProgress.has(p2.id),
212953
+ requiresManualCode: getManualCodeConfig(p2.id, origin) !== void 0 || void 0
212954
+ };
212955
+ });
212759
212956
  if (storage.getApiKeyProviders) {
212760
212957
  const apiKeyProviders = storage.getApiKeyProviders();
212761
212958
  for (const p2 of apiKeyProviders) {
@@ -223474,9 +223671,9 @@ function createApiRoutes(store, options) {
223474
223671
  return Math.max(0, Number((usedMicros / elapsedMicros * 100).toFixed(1)));
223475
223672
  };
223476
223673
  const getVitestProcessIds = async () => {
223477
- const { execFile: execFile21 } = await import("node:child_process");
223674
+ const { execFile: execFile22 } = await import("node:child_process");
223478
223675
  const stdout = await new Promise((resolve64) => {
223479
- execFile21("pgrep", ["-f", "vitest"], { encoding: "utf8" }, (err, out) => {
223676
+ execFile22("pgrep", ["-f", "vitest"], { encoding: "utf8" }, (err, out) => {
223480
223677
  resolve64(err ? "" : typeof out === "string" ? out : "");
223481
223678
  });
223482
223679
  });
@@ -234087,6 +234284,9 @@ function resolveApiType(apiType) {
234087
234284
  if (apiType === "anthropic-compatible") {
234088
234285
  return "anthropic";
234089
234286
  }
234287
+ if (apiType === "openai-responses") {
234288
+ return "openai-responses";
234289
+ }
234090
234290
  return "openai-completions";
234091
234291
  }
234092
234292
  function toProviderConfig(provider) {
@@ -234114,30 +234314,34 @@ function providersDiffer(previous, current) {
234114
234314
  return JSON.stringify(toProviderConfig(previous)) !== JSON.stringify(toProviderConfig(current));
234115
234315
  }
234116
234316
  function registerCustomProviders(modelRegistry, customProviders, logFn) {
234117
- for (const provider of customProviders ?? []) {
234317
+ const providers = customProviders ?? [];
234318
+ for (const provider of providers) {
234319
+ const registryKey2 = customProviderRegistryKey(provider, providers);
234118
234320
  try {
234119
- modelRegistry.registerProvider(provider.id, toProviderConfig(provider));
234120
- logFn(`Registered custom provider ${provider.id}`);
234321
+ modelRegistry.registerProvider(registryKey2, toProviderConfig(provider));
234322
+ logFn(`Registered custom provider "${provider.name}" (key=${registryKey2}, id=${provider.id})`);
234121
234323
  } catch (error) {
234122
234324
  const message = error instanceof Error ? error.message : String(error);
234123
- logFn(`Failed to register custom provider ${provider.id}: ${message}`);
234325
+ logFn(`Failed to register custom provider "${provider.name}" (key=${registryKey2}, id=${provider.id}): ${message}`);
234124
234326
  }
234125
234327
  }
234126
234328
  modelRegistry.refresh();
234127
234329
  }
234128
234330
  function reregisterCustomProviders(modelRegistry, previousProviders, currentProviders, logFn) {
234129
234331
  const previousById = new Map((previousProviders ?? []).map((provider) => [provider.id, provider]));
234130
- for (const provider of currentProviders ?? []) {
234332
+ const providers = currentProviders ?? [];
234333
+ for (const provider of providers) {
234131
234334
  const previous = previousById.get(provider.id);
234132
234335
  if (previous && !providersDiffer(previous, provider)) {
234133
234336
  continue;
234134
234337
  }
234338
+ const registryKey2 = customProviderRegistryKey(provider, providers);
234135
234339
  try {
234136
- modelRegistry.registerProvider(provider.id, toProviderConfig(provider));
234137
- logFn(`${previous ? "Updated" : "Registered"} custom provider ${provider.id}`);
234340
+ modelRegistry.registerProvider(registryKey2, toProviderConfig(provider));
234341
+ logFn(`${previous ? "Updated" : "Registered"} custom provider "${provider.name}" (key=${registryKey2}, id=${provider.id})`);
234138
234342
  } catch (error) {
234139
234343
  const message = error instanceof Error ? error.message : String(error);
234140
- logFn(`Failed to register custom provider ${provider.id}: ${message}`);
234344
+ logFn(`Failed to register custom provider "${provider.name}" (key=${registryKey2}, id=${provider.id}): ${message}`);
234141
234345
  }
234142
234346
  }
234143
234347
  modelRegistry.refresh();
@@ -234145,6 +234349,7 @@ function reregisterCustomProviders(modelRegistry, previousProviders, currentProv
234145
234349
  var init_custom_provider_registry = __esm({
234146
234350
  "src/commands/custom-provider-registry.ts"() {
234147
234351
  "use strict";
234352
+ init_src();
234148
234353
  }
234149
234354
  });
234150
234355
 
@@ -234699,7 +234904,7 @@ function SystemPanel({ state, isFocused }) {
234699
234904
  info.authToken ? /* @__PURE__ */ jsxs(Text, { children: [
234700
234905
  " \xB7 ",
234701
234906
  /* @__PURE__ */ jsx(Text, { color: "cyanBright", children: "[c]" }),
234702
- " copy token \xB7 drag to select"
234907
+ " copy token \xB7 select token text to copy manually"
234703
234908
  ] }) : /* @__PURE__ */ jsx(Text, { children: " \xB7 drag to select" })
234704
234909
  ] }) })
234705
234910
  ] }) });
@@ -235056,7 +235261,8 @@ function StatusModeGrid({
235056
235261
  const cols = stdout?.columns ?? 80;
235057
235262
  const middleHeight = Math.max(1, rows - 2);
235058
235263
  const systemFocused = focused === "system";
235059
- const SYSTEM_HEIGHT = (state.systemInfo?.authToken ? 5 : 4) + (systemFocused ? 1 : 0);
235264
+ const systemContentRows = estimateSystemContentRows(state.systemInfo, cols, systemFocused);
235265
+ const SYSTEM_HEIGHT = systemContentRows + 3 + (systemFocused ? 1 : 0);
235060
235266
  const bottomShare = Math.min(10, Math.max(6, Math.floor(middleHeight * 0.35)));
235061
235267
  const logsShare = Math.max(1, middleHeight - SYSTEM_HEIGHT - bottomShare);
235062
235268
  const logsAvailableRows = Math.max(1, logsShare - 4);
@@ -237982,7 +238188,7 @@ var init_app = __esm({
237982
238188
  // src/commands/dashboard-tui/controller.ts
237983
238189
  import os10 from "node:os";
237984
238190
  import v82 from "node:v8";
237985
- import { execFile as execFile20 } from "node:child_process";
238191
+ import { execFile as execFile21 } from "node:child_process";
237986
238192
  import { appendFileSync as appendFileSync2 } from "node:fs";
237987
238193
  function getAvailableMemory() {
237988
238194
  const fn2 = os10.availableMemory;
@@ -238251,7 +238457,7 @@ var init_controller = __esm({
238251
238457
  }
238252
238458
  const selfPid = process.pid;
238253
238459
  const stdout = await new Promise((resolve64) => {
238254
- execFile20("pgrep", ["-f", "vitest"], { encoding: "utf8" }, (err, out) => {
238460
+ execFile21("pgrep", ["-f", "vitest"], { encoding: "utf8" }, (err, out) => {
238255
238461
  resolve64(err ? "" : typeof out === "string" ? out : "");
238256
238462
  });
238257
238463
  });