@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/extension.js CHANGED
@@ -2070,7 +2070,31 @@ Do NOT spend time on nits when no real issues exist.`
2070
2070
  ];
2071
2071
  DEFAULT_HEARTBEAT_PROCEDURE_PATH = ".fusion/HEARTBEAT.md";
2072
2072
  DASHBOARD_USER_ID = "dashboard";
2073
- DASHBOARD_USER_ALIASES = /* @__PURE__ */ new Set([DASHBOARD_USER_ID, "user:dashboard", "User: user:dashboard"]);
2073
+ DASHBOARD_USER_ALIASES = /* @__PURE__ */ new Set([DASHBOARD_USER_ID, "user", "user:dashboard", "User: user:dashboard"]);
2074
+ }
2075
+ });
2076
+
2077
+ // ../core/src/custom-provider-key.ts
2078
+ function slugifyProviderName(name) {
2079
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
2080
+ }
2081
+ function customProviderRegistryKey(provider, allProviders) {
2082
+ const base = slugifyProviderName(provider.name) || provider.id;
2083
+ let count = 0;
2084
+ for (const current of allProviders) {
2085
+ const currentBase = slugifyProviderName(current.name) || current.id;
2086
+ if (currentBase === base) {
2087
+ count += 1;
2088
+ }
2089
+ if (current.id === provider.id) {
2090
+ break;
2091
+ }
2092
+ }
2093
+ return count <= 1 ? base : `${base}-${count}`;
2094
+ }
2095
+ var init_custom_provider_key = __esm({
2096
+ "../core/src/custom-provider-key.ts"() {
2097
+ "use strict";
2074
2098
  }
2075
2099
  });
2076
2100
 
@@ -10497,7 +10521,7 @@ var init_message_store = __esm({
10497
10521
  }
10498
10522
  getParticipantIdsForLookup(ownerId, ownerType) {
10499
10523
  if (ownerType === "user" && ownerId === DASHBOARD_USER_ID) {
10500
- return [DASHBOARD_USER_ID, "user:dashboard", "User: user:dashboard"];
10524
+ return [DASHBOARD_USER_ID, "user", "user:dashboard", "User: user:dashboard"];
10501
10525
  }
10502
10526
  return [ownerId];
10503
10527
  }
@@ -25345,9 +25369,9 @@ var init_central_core = __esm({
25345
25369
  */
25346
25370
  async generateProjectName(projectPath) {
25347
25371
  try {
25348
- const { execFile: execFile18 } = await import("node:child_process");
25372
+ const { execFile: execFile19 } = await import("node:child_process");
25349
25373
  const { promisify: promisify50 } = await import("node:util");
25350
- const execFileAsync14 = promisify50(execFile18);
25374
+ const execFileAsync14 = promisify50(execFile19);
25351
25375
  const { stdout } = await execFileAsync14(
25352
25376
  "git",
25353
25377
  ["remote", "get-url", "origin"],
@@ -26052,9 +26076,9 @@ var init_migration = __esm({
26052
26076
  return basename5(projectPath);
26053
26077
  }
26054
26078
  try {
26055
- const { execFile: execFile18 } = await import("node:child_process");
26079
+ const { execFile: execFile19 } = await import("node:child_process");
26056
26080
  const { promisify: promisify50 } = await import("node:util");
26057
- const execFileAsync14 = promisify50(execFile18);
26081
+ const execFileAsync14 = promisify50(execFile19);
26058
26082
  const { stdout } = await execFileAsync14(
26059
26083
  "git",
26060
26084
  ["remote", "get-url", "origin"],
@@ -37803,9 +37827,9 @@ async function searchWithQmd(rootDir, options) {
37803
37827
  const command = "qmd";
37804
37828
  const limit = Math.max(1, Math.min(options.limit ?? 5, 20));
37805
37829
  try {
37806
- const { execFile: execFile18 } = await import("node:child_process");
37830
+ const { execFile: execFile19 } = await import("node:child_process");
37807
37831
  const { promisify: promisify50 } = await import("node:util");
37808
- const execFileAsync14 = promisify50(execFile18);
37832
+ const execFileAsync14 = promisify50(execFile19);
37809
37833
  await ensureQmdProjectMemoryCollection(rootDir, execFileAsync14);
37810
37834
  scheduleQmdProjectMemoryRefresh(rootDir);
37811
37835
  const args = buildQmdSearchArgs(rootDir, options);
@@ -37855,9 +37879,9 @@ ${stderr}`)) {
37855
37879
  return collectionName;
37856
37880
  }
37857
37881
  async function getDefaultExecFileAsync() {
37858
- const { execFile: execFile18 } = await import("node:child_process");
37882
+ const { execFile: execFile19 } = await import("node:child_process");
37859
37883
  const { promisify: promisify50 } = await import("node:util");
37860
- return promisify50(execFile18);
37884
+ return promisify50(execFile19);
37861
37885
  }
37862
37886
  async function refreshQmdProjectMemoryIndex(rootDir, options) {
37863
37887
  const key = resolve8(rootDir);
@@ -68622,7 +68646,7 @@ var init_chat_store = __esm({
68622
68646
  *
68623
68647
  * @param sessionId - Session ID
68624
68648
  * @param filter - Optional filter (limit, offset, before cursor)
68625
- * @returns Array of messages ordered by createdAt ASC
68649
+ * @returns Array of messages ordered by createdAt ASC (default) or DESC
68626
68650
  */
68627
68651
  getMessages(sessionId, filter) {
68628
68652
  const whereClauses = ["sessionId = ?"];
@@ -68634,10 +68658,11 @@ var init_chat_store = __esm({
68634
68658
  const whereSql = whereClauses.join(" AND ");
68635
68659
  const limit = filter?.limit ?? 100;
68636
68660
  const offset = filter?.offset ?? 0;
68661
+ const order = filter?.order === "desc" ? "DESC" : "ASC";
68637
68662
  const rows = this.db.prepare(`
68638
68663
  SELECT * FROM chat_messages
68639
68664
  WHERE ${whereSql}
68640
- ORDER BY createdAt ASC
68665
+ ORDER BY createdAt ${order}
68641
68666
  LIMIT ? OFFSET ?
68642
68667
  `).all(...params, limit, offset);
68643
68668
  return rows.map((row) => this.rowToMessage(row));
@@ -69670,6 +69695,7 @@ __export(src_exports, {
69670
69695
  createSecretCipher: () => createSecretCipher,
69671
69696
  createTaskMetadataSnapshot: () => createTaskMetadataSnapshot,
69672
69697
  currentBackupTimestamp: () => currentBackupTimestamp,
69698
+ customProviderRegistryKey: () => customProviderRegistryKey,
69673
69699
  dailyMemoryPath: () => dailyMemoryPath,
69674
69700
  detectDependencyCycle: () => detectDependencyCycle,
69675
69701
  detectFnBinary: () => detectFnBinary,
@@ -69995,6 +70021,7 @@ var init_src = __esm({
69995
70021
  "use strict";
69996
70022
  init_types();
69997
70023
  init_types();
70024
+ init_custom_provider_key();
69998
70025
  init_mock_provider_constants();
69999
70026
  init_worktrunk_settings();
70000
70027
  init_agent_memory_mode();
@@ -72349,7 +72376,7 @@ var init_workflow_step_tool_policy = __esm({
72349
72376
 
72350
72377
  // ../engine/src/pi.ts
72351
72378
  import { existsSync as existsSync25, readFileSync as readFileSync10 } from "node:fs";
72352
- import { exec as exec2 } from "node:child_process";
72379
+ import { exec as exec2, execFile as execFile3 } from "node:child_process";
72353
72380
  import { promisify as promisify3 } from "node:util";
72354
72381
  import { createRequire as createRequire3 } from "node:module";
72355
72382
  import { basename as basename9, dirname as dirname11, join as join31, relative as relative4, isAbsolute as isAbsolute8, resolve as resolve15 } from "node:path";
@@ -72372,6 +72399,60 @@ import {
72372
72399
  SessionManager,
72373
72400
  SettingsManager
72374
72401
  } from "@mariozechner/pi-coding-agent";
72402
+ function normalizeRtkRewriteOptions(options) {
72403
+ const modeEnv = process.env.FUSION_RTK_REWRITE?.toLowerCase();
72404
+ const envMode = modeEnv === "1" || modeEnv === "true" || modeEnv === "rewrite" ? "rewrite" : "off";
72405
+ const envTimeoutMs = Number.parseInt(process.env.FUSION_RTK_REWRITE_TIMEOUT_MS ?? "2000", 10);
72406
+ const requestedTimeoutMs = options?.timeoutMs ?? envTimeoutMs;
72407
+ return {
72408
+ mode: options?.mode ?? envMode,
72409
+ timeoutMs: Number.isFinite(requestedTimeoutMs) && requestedTimeoutMs > 0 ? requestedTimeoutMs : 2e3
72410
+ };
72411
+ }
72412
+ function resolveRtkRewriteOptions() {
72413
+ return normalizeRtkRewriteOptions();
72414
+ }
72415
+ function getRtkErrorCode(error) {
72416
+ if (!error) return 0;
72417
+ const rawCode = error.code;
72418
+ if (typeof rawCode === "number" || typeof rawCode === "string") return rawCode;
72419
+ return null;
72420
+ }
72421
+ function shouldWarnForRtkFailure(code) {
72422
+ if (typeof code === "number") return !RTK_EXPECTED_PASSTHROUGH_EXIT_CODES.has(code);
72423
+ if (typeof code === "string") return !RTK_EXPECTED_FAIL_OPEN_ERROR_CODES.has(code);
72424
+ return true;
72425
+ }
72426
+ function rewriteCommandWithRtk(command, options, signal) {
72427
+ if (signal?.aborted) {
72428
+ return Promise.resolve(null);
72429
+ }
72430
+ return new Promise((resolve32) => {
72431
+ execFile3(
72432
+ "rtk",
72433
+ ["rewrite", command],
72434
+ {
72435
+ timeout: options.timeoutMs,
72436
+ maxBuffer: RTK_REWRITE_MAX_BUFFER_BYTES,
72437
+ signal,
72438
+ windowsHide: true
72439
+ },
72440
+ (error, stdout, stderr) => {
72441
+ const code = getRtkErrorCode(error);
72442
+ if (typeof code !== "number" || !RTK_ACCEPTED_REWRITE_EXIT_CODES.has(code)) {
72443
+ if (shouldWarnForRtkFailure(code)) {
72444
+ const reason = stderr?.toString().trim() || (error instanceof Error ? error.message : `exit ${String(code)}`);
72445
+ piLog.warn(`[pi] rtk rewrite failed open: ${reason}`);
72446
+ }
72447
+ resolve32(null);
72448
+ return;
72449
+ }
72450
+ const rewritten = stdout.toString().trim();
72451
+ resolve32(rewritten && rewritten !== command ? rewritten : null);
72452
+ }
72453
+ );
72454
+ });
72455
+ }
72375
72456
  function setHostExtensionPaths(paths) {
72376
72457
  hostExtensionPaths = [...paths];
72377
72458
  }
@@ -73272,6 +73353,36 @@ function wrapToolsWithBoundary(tools, worktreePath, projectRoot) {
73272
73353
  };
73273
73354
  });
73274
73355
  }
73356
+ function wrapToolsWithRtkRewrite(tools, options = resolveRtkRewriteOptions()) {
73357
+ const resolvedOptions = normalizeRtkRewriteOptions(options);
73358
+ if (resolvedOptions.mode !== "rewrite") {
73359
+ return tools;
73360
+ }
73361
+ return tools.map((tool) => {
73362
+ if (tool.name !== "bash") {
73363
+ return tool;
73364
+ }
73365
+ const originalExecute = tool.execute;
73366
+ return {
73367
+ ...tool,
73368
+ execute: async (...args) => {
73369
+ const params = args[1];
73370
+ const command = params?.command;
73371
+ if (typeof command !== "string" || !command.trim()) {
73372
+ return originalExecute(...args);
73373
+ }
73374
+ const signal = args[2];
73375
+ const rewrittenCommand = await rewriteCommandWithRtk(command, resolvedOptions, signal);
73376
+ if (!rewrittenCommand) {
73377
+ return originalExecute(...args);
73378
+ }
73379
+ const rewrittenArgs = [...args];
73380
+ rewrittenArgs[1] = { ...params ?? {}, command: rewrittenCommand };
73381
+ return originalExecute(...rewrittenArgs);
73382
+ }
73383
+ };
73384
+ });
73385
+ }
73275
73386
  function wrapToolsWithPermanentAgentGating(tools, gating) {
73276
73387
  if (!gating) {
73277
73388
  return tools;
@@ -73407,11 +73518,13 @@ async function createFnAgent2(options) {
73407
73518
  const modelRegistry = ModelRegistry.create(authStorage, getModelRegistryModelsPath());
73408
73519
  const resolvedProjectRoot = getProjectRootFromWorktree(options.cwd) ?? resolvePiExtensionProjectRoot(options.cwd);
73409
73520
  await registerExtensionProviders(resolvedProjectRoot, modelRegistry);
73410
- for (const provider of readCustomProviders()) {
73521
+ const customProviders = readCustomProviders();
73522
+ for (const provider of customProviders) {
73411
73523
  try {
73412
- modelRegistry.registerProvider(provider.id, {
73524
+ const registryKey2 = customProviderRegistryKey(provider, customProviders);
73525
+ modelRegistry.registerProvider(registryKey2, {
73413
73526
  baseUrl: provider.baseUrl,
73414
- api: provider.apiType === "anthropic-compatible" ? "anthropic" : "openai-completions",
73527
+ api: provider.apiType === "anthropic-compatible" ? "anthropic" : provider.apiType === "openai-responses" ? "openai-responses" : "openai-completions",
73415
73528
  apiKey: provider.apiKey,
73416
73529
  models: (provider.models ?? []).map((model) => ({
73417
73530
  id: model.id,
@@ -73428,10 +73541,11 @@ async function createFnAgent2(options) {
73428
73541
  maxTokens: 16384
73429
73542
  }))
73430
73543
  });
73431
- piLog.log(`Registered custom provider ${provider.id}`);
73544
+ piLog.log(`Registered custom provider "${provider.name}" (key=${registryKey2}, id=${provider.id})`);
73432
73545
  } catch (error) {
73433
73546
  const message = error instanceof Error ? error.message : String(error);
73434
- piLog.warn(`Failed to register custom provider ${provider.id}: ${message}`);
73547
+ const registryKey2 = customProviderRegistryKey(provider, customProviders);
73548
+ piLog.warn(`Failed to register custom provider "${provider.name}" (key=${registryKey2}, id=${provider.id}): ${message}`);
73435
73549
  }
73436
73550
  }
73437
73551
  modelRegistry.refresh();
@@ -73550,8 +73664,9 @@ async function createFnAgent2(options) {
73550
73664
  ...tools,
73551
73665
  ...readonlyFilteredCustomTools.allowed
73552
73666
  ];
73667
+ const toolsWithRtkRewrite = wrapToolsWithRtkRewrite(toolChainStart);
73553
73668
  const toolsWithPermanentGating = wrapToolsWithPermanentAgentGating(
73554
- toolChainStart,
73669
+ toolsWithRtkRewrite,
73555
73670
  options.permanentAgentGating
73556
73671
  );
73557
73672
  const toolsWithActionGate = wrapToolsWithActionGate(
@@ -73818,7 +73933,7 @@ async function createFnAgent2(options) {
73818
73933
  });
73819
73934
  return { session: promptableSession, sessionFile: promptableSession.sessionFile };
73820
73935
  }
73821
- 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;
73936
+ 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;
73822
73937
  var init_pi = __esm({
73823
73938
  "../engine/src/pi.ts"() {
73824
73939
  "use strict";
@@ -73832,6 +73947,10 @@ var init_pi = __esm({
73832
73947
  init_permanent_agent_gating();
73833
73948
  init_workflow_step_tool_policy();
73834
73949
  execAsync = promisify3(exec2);
73950
+ RTK_ACCEPTED_REWRITE_EXIT_CODES = /* @__PURE__ */ new Set([0, 3]);
73951
+ RTK_EXPECTED_PASSTHROUGH_EXIT_CODES = /* @__PURE__ */ new Set([1, 2]);
73952
+ RTK_EXPECTED_FAIL_OPEN_ERROR_CODES = /* @__PURE__ */ new Set(["ABORT_ERR", "ENOENT", "ETIMEDOUT"]);
73953
+ RTK_REWRITE_MAX_BUFFER_BYTES = 64 * 1024;
73835
73954
  hostExtensionPaths = [];
73836
73955
  FN_MEMORY_APPEND_TOOL_NAME = "fn_memory_append";
73837
73956
  FUSION_SHUTDOWN_WRAP_FLAG = "__fusionSessionShutdownDisposeWrapped";
@@ -75435,9 +75554,9 @@ async function refreshAgentMemoryQmdIndex(rootDir, agentMemory) {
75435
75554
  return;
75436
75555
  }
75437
75556
  const promise = (async () => {
75438
- const { execFile: execFile18 } = await import("node:child_process");
75557
+ const { execFile: execFile19 } = await import("node:child_process");
75439
75558
  const { promisify: promisify50 } = await import("node:util");
75440
- const execFileAsync14 = promisify50(execFile18);
75559
+ const execFileAsync14 = promisify50(execFile19);
75441
75560
  try {
75442
75561
  await execFileAsync14("qmd", buildQmdAgentMemoryCollectionAddArgs(rootDir, agentMemory.agentId), {
75443
75562
  cwd: rootDir,
@@ -75508,9 +75627,9 @@ async function searchAgentMemoryWithQmd(rootDir, agentMemory, query, limit) {
75508
75627
  }
75509
75628
  try {
75510
75629
  await refreshAgentMemoryQmdIndex(rootDir, agentMemory);
75511
- const { execFile: execFile18 } = await import("node:child_process");
75630
+ const { execFile: execFile19 } = await import("node:child_process");
75512
75631
  const { promisify: promisify50 } = await import("node:util");
75513
- const execFileAsync14 = promisify50(execFile18);
75632
+ const execFileAsync14 = promisify50(execFile19);
75514
75633
  const { stdout } = await execFileAsync14("qmd", buildQmdAgentMemorySearchArgs(rootDir, agentMemory.agentId, query, limit), {
75515
75634
  cwd: rootDir,
75516
75635
  timeout: 4e3,
@@ -79566,6 +79685,69 @@ var init_oauth_expiry_monitor = __esm({
79566
79685
  }
79567
79686
  });
79568
79687
 
79688
+ // ../engine/src/notification/oauth-validity-logger.ts
79689
+ var DEFAULT_INTERVAL_MS2, OAuthValidityLogger;
79690
+ var init_oauth_validity_logger = __esm({
79691
+ "../engine/src/notification/oauth-validity-logger.ts"() {
79692
+ "use strict";
79693
+ init_logger2();
79694
+ DEFAULT_INTERVAL_MS2 = 24 * 60 * 60 * 1e3;
79695
+ OAuthValidityLogger = class {
79696
+ constructor(opts) {
79697
+ this.opts = opts;
79698
+ this.intervalMs = opts.intervalMs ?? DEFAULT_INTERVAL_MS2;
79699
+ this.clock = opts.clock ?? Date.now;
79700
+ this.logger = opts.logger ?? ((message, meta) => schedulerLog.warn(message, meta));
79701
+ }
79702
+ intervalMs;
79703
+ clock;
79704
+ logger;
79705
+ timer = null;
79706
+ async start() {
79707
+ if (this.timer) {
79708
+ return;
79709
+ }
79710
+ await this.check();
79711
+ this.timer = setInterval(() => {
79712
+ void this.check();
79713
+ }, this.intervalMs);
79714
+ this.timer.unref?.();
79715
+ }
79716
+ stop() {
79717
+ if (!this.timer) {
79718
+ return;
79719
+ }
79720
+ clearInterval(this.timer);
79721
+ this.timer = null;
79722
+ }
79723
+ async check() {
79724
+ this.opts.authStorage.reload?.();
79725
+ const providers = this.opts.authStorage.getOAuthProviders?.() ?? [];
79726
+ const now = this.clock();
79727
+ for (const provider of providers) {
79728
+ try {
79729
+ const credential = this.opts.authStorage.get?.(provider.id);
79730
+ if (credential?.type !== "oauth" || typeof credential.expires !== "number") {
79731
+ continue;
79732
+ }
79733
+ if (credential.expires > now) {
79734
+ continue;
79735
+ }
79736
+ this.logger("oauth credential expired \u2014 provider re-login required", {
79737
+ providerId: provider.id,
79738
+ providerName: provider.name,
79739
+ expiresAt: new Date(credential.expires).toISOString()
79740
+ });
79741
+ } catch (error) {
79742
+ const message = error instanceof Error ? error.message : String(error);
79743
+ schedulerLog.warn(`OAuth validity logger failed for provider=${provider.id}: ${message}`);
79744
+ }
79745
+ }
79746
+ }
79747
+ };
79748
+ }
79749
+ });
79750
+
79569
79751
  // ../engine/src/notification/index.ts
79570
79752
  var init_notification = __esm({
79571
79753
  "../engine/src/notification/index.ts"() {
@@ -79574,6 +79756,7 @@ var init_notification = __esm({
79574
79756
  init_webhook_provider();
79575
79757
  init_notification_service();
79576
79758
  init_oauth_expiry_monitor();
79759
+ init_oauth_validity_logger();
79577
79760
  }
79578
79761
  });
79579
79762
 
@@ -83389,7 +83572,7 @@ ${getErrorStderr(error) ?? ""}`;
83389
83572
  import { createHash as createHash9 } from "node:crypto";
83390
83573
  import { promises as fs5 } from "node:fs";
83391
83574
  import path2 from "node:path";
83392
- import { execFile as execFile3 } from "node:child_process";
83575
+ import { execFile as execFile4 } from "node:child_process";
83393
83576
  function isValidFilename(filename) {
83394
83577
  return !!filename && !filename.includes("/") && !filename.includes("\\") && !filename.includes("..") && !filename.includes("\0") && filename !== FINGERPRINT_FILE;
83395
83578
  }
@@ -83450,7 +83633,7 @@ async function writeSecretsEnvFile(opts) {
83450
83633
  } catch {
83451
83634
  }
83452
83635
  if (cfg?.requireGitignored !== false) {
83453
- const check = await checkIgnored(opts.execFileImpl ?? execFile3, opts.worktreePath, filename);
83636
+ const check = await checkIgnored(opts.execFileImpl ?? execFile4, opts.worktreePath, filename);
83454
83637
  if (!check.ignored) {
83455
83638
  await opts.audit?.filesystem({ type: "secret:env-write-skipped", target: opts.taskId, metadata: { filename, reason: "not-gitignored", overwritePolicy, checkIgnoreError: check.error } });
83456
83639
  return { outcome: "skipped", filename, reason: "not-gitignored" };
@@ -88398,7 +88581,7 @@ var init_session_token_usage = __esm({
88398
88581
  });
88399
88582
 
88400
88583
  // ../engine/src/merger-squash-audit.ts
88401
- import { execFile as execFile5 } from "node:child_process";
88584
+ import { execFile as execFile6 } from "node:child_process";
88402
88585
  import { promisify as promisify24 } from "node:util";
88403
88586
  async function auditSquashMerge(input) {
88404
88587
  const normalizedLookback = normalizeMergeOverlapLookback(input.lookback);
@@ -88554,14 +88737,14 @@ var execFileAsync, MERGER_MAIN_OVERLAP_LOOKBACK_COMMITS, GIT_OUTPUT_MAX_BUFFER;
88554
88737
  var init_merger_squash_audit = __esm({
88555
88738
  "../engine/src/merger-squash-audit.ts"() {
88556
88739
  "use strict";
88557
- execFileAsync = promisify24(execFile5);
88740
+ execFileAsync = promisify24(execFile6);
88558
88741
  MERGER_MAIN_OVERLAP_LOOKBACK_COMMITS = 30;
88559
88742
  GIT_OUTPUT_MAX_BUFFER = 10 * 1024 * 1024;
88560
88743
  }
88561
88744
  });
88562
88745
 
88563
88746
  // ../engine/src/merger-overlap-guard.ts
88564
- import { execFile as execFile6 } from "node:child_process";
88747
+ import { execFile as execFile7 } from "node:child_process";
88565
88748
  import { promisify as promisify25 } from "node:util";
88566
88749
  async function getBranchTouchedFiles({
88567
88750
  rootDir,
@@ -88687,13 +88870,13 @@ var init_merger_overlap_guard = __esm({
88687
88870
  "use strict";
88688
88871
  init_logger2();
88689
88872
  init_merger_squash_audit();
88690
- execFileAsync2 = promisify25(execFile6);
88873
+ execFileAsync2 = promisify25(execFile7);
88691
88874
  GIT_OUTPUT_MAX_BUFFER2 = 10 * 1024 * 1024;
88692
88875
  }
88693
88876
  });
88694
88877
 
88695
88878
  // ../engine/src/merger-diff-volume-gate.ts
88696
- import { execFile as execFile7 } from "node:child_process";
88879
+ import { execFile as execFile8 } from "node:child_process";
88697
88880
  import { promisify as promisify26 } from "node:util";
88698
88881
  function buildMessage(findings) {
88699
88882
  const details = findings.map((finding) => `${finding.file} (branch_net=${finding.branchNet}, staged=${finding.staged}, ratio=${finding.ratio.toFixed(3)})`).join(", ");
@@ -88755,7 +88938,7 @@ var init_merger_diff_volume_gate = __esm({
88755
88938
  "../engine/src/merger-diff-volume-gate.ts"() {
88756
88939
  "use strict";
88757
88940
  init_merger();
88758
- execFileAsync3 = promisify26(execFile7);
88941
+ execFileAsync3 = promisify26(execFile8);
88759
88942
  DiffVolumeRegressionError = class extends Error {
88760
88943
  constructor(findings) {
88761
88944
  super(buildMessage(findings));
@@ -89416,7 +89599,7 @@ var init_mesh_lease_manager = __esm({
89416
89599
 
89417
89600
  // ../engine/src/merger-integration-worktree.ts
89418
89601
  import { createHash as createHash10 } from "node:crypto";
89419
- import { exec as exec25, execFile as execFile8 } from "node:child_process";
89602
+ import { exec as exec25, execFile as execFile9 } from "node:child_process";
89420
89603
  import { promisify as promisify29 } from "node:util";
89421
89604
  function quoteAutostashArg(value) {
89422
89605
  return `"${value.replace(/(["\\$`])/g, "\\$1")}"`;
@@ -89895,7 +90078,7 @@ var init_merger_integration_worktree = __esm({
89895
90078
  init_worktree_pool();
89896
90079
  init_worktree_names();
89897
90080
  execAsync23 = promisify29(exec25);
89898
- execFileAsync4 = promisify29(execFile8);
90081
+ execFileAsync4 = promisify29(execFile9);
89899
90082
  MERGE_HANDOFF_WORKER_ID = "merger-reuse-handoff";
89900
90083
  MergeHandoffRefusedError = class extends Error {
89901
90084
  reason;
@@ -90608,7 +90791,7 @@ var init_worktree_acquisition = __esm({
90608
90791
  });
90609
90792
 
90610
90793
  // ../engine/src/merger-ref-update-advance.ts
90611
- import { execFile as execFile9 } from "node:child_process";
90794
+ import { execFile as execFile10 } from "node:child_process";
90612
90795
  import { promisify as promisify31 } from "node:util";
90613
90796
  async function runGit3(args, cwd) {
90614
90797
  return await execFileAsync5("git", args, {
@@ -90752,7 +90935,7 @@ var execFileAsync5, testHooks, IntegrationBranchConcurrentAdvanceError;
90752
90935
  var init_merger_ref_update_advance = __esm({
90753
90936
  "../engine/src/merger-ref-update-advance.ts"() {
90754
90937
  "use strict";
90755
- execFileAsync5 = promisify31(execFile9);
90938
+ execFileAsync5 = promisify31(execFile10);
90756
90939
  testHooks = {
90757
90940
  runGit: runGit3
90758
90941
  };
@@ -90779,7 +90962,7 @@ var init_merger_ref_update_advance = __esm({
90779
90962
  });
90780
90963
 
90781
90964
  // ../engine/src/worktree-ref-sync.ts
90782
- import { execFile as execFile10, spawn as spawn5 } from "node:child_process";
90965
+ import { execFile as execFile11, spawn as spawn5 } from "node:child_process";
90783
90966
  import { promisify as promisify32 } from "node:util";
90784
90967
  import { copyFileSync, existsSync as existsSync36, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync2, readFileSync as readFileSync11, rmSync as rmSync3, writeFileSync as writeFileSync2 } from "node:fs";
90785
90968
  import { dirname as dirname17, join as join40 } from "node:path";
@@ -91023,7 +91206,7 @@ var execFileAsync6;
91023
91206
  var init_worktree_ref_sync = __esm({
91024
91207
  "../engine/src/worktree-ref-sync.ts"() {
91025
91208
  "use strict";
91026
- execFileAsync6 = promisify32(execFile10);
91209
+ execFileAsync6 = promisify32(execFile11);
91027
91210
  }
91028
91211
  });
91029
91212
 
@@ -91294,7 +91477,7 @@ __export(merger_exports, {
91294
91477
  tryFastForwardFromOrigin: () => tryFastForwardFromOrigin,
91295
91478
  validateDiffScope: () => validateDiffScope
91296
91479
  });
91297
- import { execSync as execSync4, exec as exec28, execFile as execFile11 } from "node:child_process";
91480
+ import { execSync as execSync4, exec as exec28, execFile as execFile12 } from "node:child_process";
91298
91481
  import { promisify as promisify34 } from "node:util";
91299
91482
  import { existsSync as existsSync37, readFileSync as readFileSync12, readdirSync as readdirSync5, writeFileSync as writeFileSync3, unlinkSync, renameSync as renameSync2 } from "node:fs";
91300
91483
  import { createHash as createHash11 } from "node:crypto";
@@ -99734,7 +99917,7 @@ var init_merger = __esm({
99734
99917
  init_merger_diff_volume_gate();
99735
99918
  init_merger_ref_update_advance();
99736
99919
  execAsync26 = promisify34(exec28);
99737
- execFileAsync7 = promisify34(execFile11);
99920
+ execFileAsync7 = promisify34(execFile12);
99738
99921
  LOCKFILE_PATTERNS = [
99739
99922
  "package-lock.json",
99740
99923
  "pnpm-lock.yaml",
@@ -108782,7 +108965,7 @@ Take a completely different approach to writing this specification. Do NOT repea
108782
108965
  });
108783
108966
 
108784
108967
  // ../engine/src/merger-orphan-rehome.ts
108785
- import { execFile as execFile12 } from "node:child_process";
108968
+ import { execFile as execFile13 } from "node:child_process";
108786
108969
  import { promisify as promisify37 } from "node:util";
108787
108970
  async function runGit5(args, cwd) {
108788
108971
  const { stdout } = await execFileAsync8("git", args, {
@@ -108888,7 +109071,7 @@ var init_merger_orphan_rehome = __esm({
108888
109071
  "../engine/src/merger-orphan-rehome.ts"() {
108889
109072
  "use strict";
108890
109073
  init_merger_ref_update_advance();
108891
- execFileAsync8 = promisify37(execFile12);
109074
+ execFileAsync8 = promisify37(execFile13);
108892
109075
  }
108893
109076
  });
108894
109077
 
@@ -121795,7 +121978,7 @@ ${taskContext}` : ""}`;
121795
121978
  });
121796
121979
 
121797
121980
  // ../engine/src/smart-pull.ts
121798
- import { execFile as execFile13 } from "node:child_process";
121981
+ import { execFile as execFile14 } from "node:child_process";
121799
121982
  import { promisify as promisify41 } from "node:util";
121800
121983
  async function runGit6(args, cwd, timeoutMs) {
121801
121984
  const result = await execFileAsync9("git", args, {
@@ -121953,7 +122136,7 @@ var execFileAsync9;
121953
122136
  var init_smart_pull = __esm({
121954
122137
  "../engine/src/smart-pull.ts"() {
121955
122138
  "use strict";
121956
- execFileAsync9 = promisify41(execFile13);
122139
+ execFileAsync9 = promisify41(execFile14);
121957
122140
  }
121958
122141
  });
121959
122142
 
@@ -134233,7 +134416,7 @@ var init_provider_adapters = __esm({
134233
134416
 
134234
134417
  // ../engine/src/remote-access/tunnel-process-manager.ts
134235
134418
  import { EventEmitter as EventEmitter24 } from "node:events";
134236
- import { exec as exec36, execFile as execFile14, spawn as spawn8 } from "node:child_process";
134419
+ import { exec as exec36, execFile as execFile15, spawn as spawn8 } from "node:child_process";
134237
134420
  import { promisify as promisify43 } from "node:util";
134238
134421
  function nowIso2() {
134239
134422
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -134283,7 +134466,7 @@ var init_tunnel_process_manager = __esm({
134283
134466
  init_provider_adapters();
134284
134467
  DEFAULT_MAX_LOG_ENTRIES = 400;
134285
134468
  DEFAULT_STOP_TIMEOUT_MS2 = 5e3;
134286
- execFileAsync10 = promisify43(execFile14);
134469
+ execFileAsync10 = promisify43(execFile15);
134287
134470
  execAsync32 = promisify43(exec36);
134288
134471
  LineBuffer = class {
134289
134472
  pending = "";
@@ -134685,7 +134868,7 @@ var init_tunnel_process_manager = __esm({
134685
134868
  });
134686
134869
 
134687
134870
  // ../engine/src/project-engine.ts
134688
- import { execFile as execFile15 } from "node:child_process";
134871
+ import { execFile as execFile16 } from "node:child_process";
134689
134872
  import { promisify as promisify44 } from "node:util";
134690
134873
  function formatErrorDetails(error) {
134691
134874
  if (error instanceof Error) {
@@ -134733,7 +134916,7 @@ var init_project_engine = __esm({
134733
134916
  init_run_audit();
134734
134917
  init_verification_followup_dedup();
134735
134918
  init_tunnel_process_manager();
134736
- execFileAsync11 = promisify44(execFile15);
134919
+ execFileAsync11 = promisify44(execFile16);
134737
134920
  MERGE_HANDOFF_GRACE_MS = 300;
134738
134921
  isRemoteActive = (ra) => ra?.activeProvider != null && (ra.providers[ra.activeProvider]?.enabled ?? false);
134739
134922
  ProjectEngine = class _ProjectEngine {
@@ -134765,6 +134948,7 @@ var init_project_engine = __esm({
134765
134948
  notifier;
134766
134949
  notificationService;
134767
134950
  oauthExpiryMonitor;
134951
+ oauthValidityLogger;
134768
134952
  gridlockDetector;
134769
134953
  cronRunner;
134770
134954
  automationStore;
@@ -134878,11 +135062,14 @@ var init_project_engine = __esm({
134878
135062
  agentNameResolver
134879
135063
  });
134880
135064
  await this.notificationService.start();
135065
+ const authStorage = createFusionAuthStorage();
134881
135066
  this.oauthExpiryMonitor = new OAuthExpiryMonitor({
134882
- authStorage: createFusionAuthStorage(),
135067
+ authStorage,
134883
135068
  notificationService: this.notificationService
134884
135069
  });
134885
135070
  await this.oauthExpiryMonitor.start();
135071
+ this.oauthValidityLogger = new OAuthValidityLogger({ authStorage });
135072
+ await this.oauthValidityLogger.start();
134886
135073
  this.notifier = new NtfyNotifier(
134887
135074
  store,
134888
135075
  {
@@ -135066,6 +135253,7 @@ ${detail}`
135066
135253
  } catch {
135067
135254
  }
135068
135255
  this.oauthExpiryMonitor?.stop();
135256
+ this.oauthValidityLogger?.stop();
135069
135257
  this.notificationService?.stop();
135070
135258
  this.notifier?.stop();
135071
135259
  this.gridlockDetector?.stop();
@@ -146420,13 +146608,13 @@ var init_pr_metadata_generator = __esm({
146420
146608
  });
146421
146609
 
146422
146610
  // ../dashboard/src/routes/resolve-diff-base.ts
146423
- import { execFile as execFile16 } from "node:child_process";
146611
+ import { execFile as execFile17 } from "node:child_process";
146424
146612
  import { promisify as promisify47 } from "node:util";
146425
146613
  var execFileAsync12;
146426
146614
  var init_resolve_diff_base = __esm({
146427
146615
  "../dashboard/src/routes/resolve-diff-base.ts"() {
146428
146616
  "use strict";
146429
- execFileAsync12 = promisify47(execFile16);
146617
+ execFileAsync12 = promisify47(execFile17);
146430
146618
  }
146431
146619
  });
146432
146620
 
@@ -151662,13 +151850,13 @@ var init_register_agents_projects_nodes = __esm({
151662
151850
  });
151663
151851
 
151664
151852
  // ../dashboard/src/exec-file.ts
151665
- import { execFile as execFile17 } from "node:child_process";
151853
+ import { execFile as execFile18 } from "node:child_process";
151666
151854
  import { promisify as promisify49 } from "node:util";
151667
151855
  var execFileAsync13;
151668
151856
  var init_exec_file = __esm({
151669
151857
  "../dashboard/src/exec-file.ts"() {
151670
151858
  "use strict";
151671
- execFileAsync13 = promisify49(execFile17);
151859
+ execFileAsync13 = promisify49(execFile18);
151672
151860
  }
151673
151861
  });
151674
151862
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion/pi-claude-cli",
3
- "version": "0.34.0",
3
+ "version": "0.35.0",
4
4
  "description": "Fusion vendored fork: pi coding-agent extension that routes LLM calls through the Claude Code CLI. Forked from rchern/pi-claude-cli (MIT). See UPSTREAM.md.",
5
5
  "license": "MIT",
6
6
  "private": true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusion-plugin-examples/cli-printing-press",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "type": "module",
5
5
  "description": "CLI Printing Press plugin package for Fusion",
6
6
  "private": true,