@runfusion/fusion 0.7.0 → 0.7.1

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 (36) hide show
  1. package/dist/bin.js +2058 -1709
  2. package/dist/client/assets/{AgentDetailView-Du65-jDo.js → AgentDetailView-DyzuiJas.js} +1 -1
  3. package/dist/client/assets/AgentsView-C2f7esMv.css +1 -0
  4. package/dist/client/assets/{AgentsView-BkgNEbNs.js → AgentsView-CgweOTe6.js} +46 -46
  5. package/dist/client/assets/{ChatView-LDte0TdV.js → ChatView-DrY8FMIt.js} +1 -1
  6. package/dist/client/assets/{DevServerView-AXznq3jv.js → DevServerView-fvjo36sF.js} +1 -1
  7. package/dist/client/assets/{DirectoryPicker-CSp3G115.js → DirectoryPicker-D5KQ-im_.js} +1 -1
  8. package/dist/client/assets/{DocumentsView-DOe0E1WQ.js → DocumentsView-D2wK7FYJ.js} +1 -1
  9. package/dist/client/assets/{InsightsView-DWZbS6z-.js → InsightsView-DfY3sa1j.js} +1 -1
  10. package/dist/client/assets/{MemoryView-BxnlhBoa.js → MemoryView-CyAQgXwO.js} +1 -1
  11. package/dist/client/assets/{NodesView-DO9jxhM4.js → NodesView-g26-j7rg.js} +4 -4
  12. package/dist/client/assets/{PiExtensionsManager-CfXZaWl7.js → PiExtensionsManager-DfMr3Gls.js} +3 -3
  13. package/dist/client/assets/{PluginManager-r6CWD9u-.js → PluginManager-DiMOD-Kj.js} +1 -1
  14. package/dist/client/assets/{RoadmapsView-CgAM3YfN.js → RoadmapsView-DJC4F4CD.js} +1 -1
  15. package/dist/client/assets/SettingsModal-BnekMOV2.css +1 -0
  16. package/dist/client/assets/{SettingsModal-fmRtzH8z.js → SettingsModal-Cx3iMWDs.js} +1 -1
  17. package/dist/client/assets/SettingsModal-DjVE27r5.js +31 -0
  18. package/dist/client/assets/{SetupWizardModal-oRNpImWR.js → SetupWizardModal-Cow6woq6.js} +1 -1
  19. package/dist/client/assets/{SkillsView-BhwtL-0_.js → SkillsView-DTB2cmXQ.js} +1 -1
  20. package/dist/client/assets/{TodoView-CmhUBFNV.js → TodoView-CyxdHUdz.js} +1 -1
  21. package/dist/client/assets/{folder-open-CrTagHrr.js → folder-open-C3zB1vmh.js} +1 -1
  22. package/dist/client/assets/{index-S9oR77v2.css → index-Belw0PQt.css} +1 -1
  23. package/dist/client/assets/{index-BTeSa6vk.js → index-DJDWSrju.js} +14 -14
  24. package/dist/client/assets/{list-checks-DR26h_Io.js → list-checks-CK3_6p5e.js} +1 -1
  25. package/dist/client/assets/{star-CO_D42zy.js → star-BQhDgM9V.js} +1 -1
  26. package/dist/client/assets/{upload-BcrgS-iu.js → upload-DDdZveEJ.js} +1 -1
  27. package/dist/client/assets/{users-4d8al5Sp.js → users-DWWgd19M.js} +1 -1
  28. package/dist/client/brands/hermes-logo.svg +1 -1
  29. package/dist/client/index.html +2 -2
  30. package/dist/client/version.json +1 -1
  31. package/dist/extension.js +1340 -1126
  32. package/dist/pi-claude-cli/package.json +1 -1
  33. package/package.json +7 -6
  34. package/dist/client/assets/AgentsView-D12CuIFc.css +0 -1
  35. package/dist/client/assets/SettingsModal-DPDQyWim.css +0 -1
  36. package/dist/client/assets/SettingsModal-GZdRt8fX.js +0 -31
package/dist/extension.js CHANGED
@@ -114,6 +114,7 @@ var init_settings_schema = __esm({
114
114
  mergeStrategy: "direct",
115
115
  pushAfterMerge: false,
116
116
  pushRemote: "origin",
117
+ unavailableNodePolicy: "block",
117
118
  worktreeInitCommand: void 0,
118
119
  testCommand: void 0,
119
120
  buildCommand: void 0,
@@ -2176,9 +2177,9 @@ var init_sqlite_adapter = __esm({
2176
2177
  cachedCtor = null;
2177
2178
  DatabaseSync = class {
2178
2179
  impl;
2179
- constructor(path) {
2180
+ constructor(path2) {
2180
2181
  const Ctor = loadDatabaseCtor();
2181
- this.impl = new Ctor(path);
2182
+ this.impl = new Ctor(path2);
2182
2183
  }
2183
2184
  exec(sql) {
2184
2185
  this.impl.exec(sql);
@@ -2288,7 +2289,7 @@ var init_db = __esm({
2288
2289
  "use strict";
2289
2290
  init_sqlite_adapter();
2290
2291
  init_types();
2291
- SCHEMA_VERSION = 48;
2292
+ SCHEMA_VERSION = 49;
2292
2293
  SCHEMA_SQL = `
2293
2294
  -- Tasks table with JSON columns for nested data
2294
2295
  CREATE TABLE IF NOT EXISTS tasks (
@@ -3742,6 +3743,11 @@ CREATE INDEX IF NOT EXISTS idxTodoItemsSortOrder ON todo_items(listId, sortOrder
3742
3743
  this.addColumnIfMissing("tasks", "verificationFailureCount", "INTEGER DEFAULT 0");
3743
3744
  });
3744
3745
  }
3746
+ if (version < 49) {
3747
+ this.applyMigration(49, () => {
3748
+ this.addColumnIfMissing("tasks", "nodeId", "TEXT");
3749
+ });
3750
+ }
3745
3751
  }
3746
3752
  /**
3747
3753
  * Run a single migration step inside a transaction and bump the version.
@@ -9658,12 +9664,12 @@ var init_plugin_store = __esm({
9658
9664
  * Register a new plugin.
9659
9665
  */
9660
9666
  async registerPlugin(input) {
9661
- const { manifest, path, settings = {} } = input;
9667
+ const { manifest, path: path2, settings = {} } = input;
9662
9668
  const manifestValidation = validatePluginManifest(manifest);
9663
9669
  if (!manifestValidation.valid) {
9664
9670
  throw new Error(`Invalid plugin manifest: ${manifestValidation.errors.join(", ")}`);
9665
9671
  }
9666
- if (!path?.trim()) {
9672
+ if (!path2?.trim()) {
9667
9673
  throw new Error("Plugin path is required and cannot be empty");
9668
9674
  }
9669
9675
  if (!this.validateIdFormat(manifest.id)) {
@@ -9694,7 +9700,7 @@ var init_plugin_store = __esm({
9694
9700
  description: manifest.description,
9695
9701
  author: manifest.author,
9696
9702
  homepage: manifest.homepage,
9697
- path: path.trim(),
9703
+ path: path2.trim(),
9698
9704
  enabled: true,
9699
9705
  state: "installed",
9700
9706
  settings: mergedSettings,
@@ -14682,7 +14688,7 @@ var require_multicast_dns = __commonJS({
14682
14688
  var dgram = __require("dgram");
14683
14689
  var thunky = require_thunky();
14684
14690
  var events = __require("events");
14685
- var os2 = __require("os");
14691
+ var os3 = __require("os");
14686
14692
  var noop = function() {
14687
14693
  };
14688
14694
  module.exports = function(opts) {
@@ -14812,14 +14818,14 @@ var require_multicast_dns = __commonJS({
14812
14818
  return that;
14813
14819
  };
14814
14820
  function defaultInterface() {
14815
- var networks = os2.networkInterfaces();
14821
+ var networks = os3.networkInterfaces();
14816
14822
  var names = Object.keys(networks);
14817
14823
  for (var i = 0; i < names.length; i++) {
14818
14824
  var net = networks[names[i]];
14819
14825
  for (var j = 0; j < net.length; j++) {
14820
14826
  var iface = net[j];
14821
14827
  if (isIPv4(iface.family) && !iface.internal) {
14822
- if (os2.platform() === "darwin" && names[i] === "en0") return iface.address;
14828
+ if (os3.platform() === "darwin" && names[i] === "en0") return iface.address;
14823
14829
  return "0.0.0.0";
14824
14830
  }
14825
14831
  }
@@ -14827,7 +14833,7 @@ var require_multicast_dns = __commonJS({
14827
14833
  return "127.0.0.1";
14828
14834
  }
14829
14835
  function allInterfaces() {
14830
- var networks = os2.networkInterfaces();
14836
+ var networks = os3.networkInterfaces();
14831
14837
  var names = Object.keys(networks);
14832
14838
  var res = [];
14833
14839
  for (var i = 0; i < names.length; i++) {
@@ -15959,9 +15965,9 @@ var init_central_core = __esm({
15959
15965
  * @param path — Absolute project path
15960
15966
  * @returns The project or undefined if not found
15961
15967
  */
15962
- async getProjectByPath(path) {
15968
+ async getProjectByPath(path2) {
15963
15969
  this.ensureInitialized();
15964
- const row = this.db.prepare("SELECT * FROM projects WHERE path = ?").get(path);
15970
+ const row = this.db.prepare("SELECT * FROM projects WHERE path = ?").get(path2);
15965
15971
  if (!row) return void 0;
15966
15972
  return this.rowToProject(row);
15967
15973
  }
@@ -27886,11 +27892,11 @@ function extractDreamProcessorResult(output) {
27886
27892
  longTermUpdates: updatesMatch?.[1]?.trim() ?? ""
27887
27893
  };
27888
27894
  }
27889
- async function readIfExists(path) {
27890
- if (!existsSync9(path)) {
27895
+ async function readIfExists(path2) {
27896
+ if (!existsSync9(path2)) {
27891
27897
  return "";
27892
27898
  }
27893
- return readFile5(path, "utf-8");
27899
+ return readFile5(path2, "utf-8");
27894
27900
  }
27895
27901
  async function processMemoryDreams(rootDir, executePrompt, date = /* @__PURE__ */ new Date()) {
27896
27902
  await ensureOpenClawMemoryFiles(rootDir, date);
@@ -28271,20 +28277,20 @@ async function listProjectMemoryFiles(rootDir, date = /* @__PURE__ */ new Date()
28271
28277
  async function readProjectMemoryFile(rootDir, options) {
28272
28278
  return getMemoryFile(rootDir, options, "file");
28273
28279
  }
28274
- async function readProjectMemoryFileContent(rootDir, path) {
28275
- const { absPath, displayPath } = resolveMemoryFilePath(rootDir, path);
28280
+ async function readProjectMemoryFileContent(rootDir, path2) {
28281
+ const { absPath, displayPath } = resolveMemoryFilePath(rootDir, path2);
28276
28282
  try {
28277
28283
  const content = await readFile6(absPath, "utf-8");
28278
28284
  return { path: displayPath, content };
28279
28285
  } catch (err) {
28280
28286
  if (err.code === "ENOENT") {
28281
- throw new MemoryBackendError("NOT_FOUND", `Memory path '${path}' not found`, "file");
28287
+ throw new MemoryBackendError("NOT_FOUND", `Memory path '${path2}' not found`, "file");
28282
28288
  }
28283
- throw new MemoryBackendError("READ_FAILED", `Failed to read memory path '${path}': ${err.message}`, "file");
28289
+ throw new MemoryBackendError("READ_FAILED", `Failed to read memory path '${path2}': ${err.message}`, "file");
28284
28290
  }
28285
28291
  }
28286
- async function writeProjectMemoryFile(rootDir, path, content) {
28287
- const { absPath } = resolveMemoryFilePath(rootDir, path);
28292
+ async function writeProjectMemoryFile(rootDir, path2, content) {
28293
+ const { absPath } = resolveMemoryFilePath(rootDir, path2);
28288
28294
  await mkdir6(dirname4(absPath), { recursive: true });
28289
28295
  const tmpPath = `${absPath}.tmp`;
28290
28296
  await writeFile5(tmpPath, content, "utf-8");
@@ -28390,20 +28396,20 @@ async function resolveAgentMemoryFilePath(rootDir, agentId, requestedPath) {
28390
28396
  }
28391
28397
  return { absPath, displayPath };
28392
28398
  }
28393
- async function readAgentMemoryFile(rootDir, agentId, path) {
28394
- const { absPath, displayPath } = await resolveAgentMemoryFilePath(rootDir, agentId, path);
28399
+ async function readAgentMemoryFile(rootDir, agentId, path2) {
28400
+ const { absPath, displayPath } = await resolveAgentMemoryFilePath(rootDir, agentId, path2);
28395
28401
  try {
28396
28402
  const content = await readFile6(absPath, "utf-8");
28397
28403
  return { path: displayPath, content };
28398
28404
  } catch (err) {
28399
28405
  if (err.code === "ENOENT") {
28400
- throw new MemoryBackendError("NOT_FOUND", `Memory path '${path}' not found`, "file");
28406
+ throw new MemoryBackendError("NOT_FOUND", `Memory path '${path2}' not found`, "file");
28401
28407
  }
28402
- throw new MemoryBackendError("READ_FAILED", `Failed to read memory path '${path}': ${err.message}`, "file");
28408
+ throw new MemoryBackendError("READ_FAILED", `Failed to read memory path '${path2}': ${err.message}`, "file");
28403
28409
  }
28404
28410
  }
28405
- async function writeAgentMemoryFile(rootDir, agentId, path, content) {
28406
- const { absPath } = await resolveAgentMemoryFilePath(rootDir, agentId, path);
28411
+ async function writeAgentMemoryFile(rootDir, agentId, path2, content) {
28412
+ const { absPath } = await resolveAgentMemoryFilePath(rootDir, agentId, path2);
28407
28413
  await mkdir6(dirname4(absPath), { recursive: true });
28408
28414
  const tmpPath = `${absPath}.tmp`;
28409
28415
  await writeFile5(tmpPath, content, "utf-8");
@@ -28411,8 +28417,8 @@ async function writeAgentMemoryFile(rootDir, agentId, path, content) {
28411
28417
  await rename6(tmpPath, absPath);
28412
28418
  return { success: true };
28413
28419
  }
28414
- function isPathTraversal(path) {
28415
- return path.split(/[\\/]+/).includes("..");
28420
+ function isPathTraversal(path2) {
28421
+ return path2.split(/[\\/]+/).includes("..");
28416
28422
  }
28417
28423
  function normalizeMemoryRequestPath(rawPath) {
28418
28424
  const trimmed = rawPath.trim();
@@ -29467,14 +29473,14 @@ function assertSafeGitBranchName(name) {
29467
29473
  throw new Error(`Unsafe git branch name: ${JSON.stringify(name)}`);
29468
29474
  }
29469
29475
  }
29470
- function assertSafeAbsolutePath(path) {
29471
- const isAbsolute12 = path.startsWith("/") || /^[A-Za-z]:[\\/]/.test(path);
29472
- if (!path || path.length > 4096 || !isAbsolute12 || path.startsWith("-") || // Reject shell metacharacters, quotes, control chars, and NULs.
29476
+ function assertSafeAbsolutePath(path2) {
29477
+ const isAbsolute12 = path2.startsWith("/") || /^[A-Za-z]:[\\/]/.test(path2);
29478
+ if (!path2 || path2.length > 4096 || !isAbsolute12 || path2.startsWith("-") || // Reject shell metacharacters, quotes, control chars, and NULs.
29473
29479
  /["'`$\n\r\t;&|<>()*?[\]{}\\\0]/.test(
29474
- path.replace(/^[A-Za-z]:/, "")
29480
+ path2.replace(/^[A-Za-z]:/, "")
29475
29481
  // ignore the drive-letter colon on Windows
29476
29482
  )) {
29477
- throw new Error(`Unsafe path: ${JSON.stringify(path)}`);
29483
+ throw new Error(`Unsafe path: ${JSON.stringify(path2)}`);
29478
29484
  }
29479
29485
  }
29480
29486
  function truncateTaskLogOutcome(outcome) {
@@ -29828,6 +29834,7 @@ var init_store = __esm({
29828
29834
  sliceId: row.sliceId || void 0,
29829
29835
  assignedAgentId: row.assignedAgentId || void 0,
29830
29836
  assigneeUserId: row.assigneeUserId || void 0,
29837
+ nodeId: row.nodeId || void 0,
29831
29838
  checkedOutBy: row.checkedOutBy || void 0,
29832
29839
  checkedOutAt: row.checkedOutAt || void 0
29833
29840
  };
@@ -30075,6 +30082,7 @@ ${recentText}` : void 0
30075
30082
  "sliceId",
30076
30083
  "assignedAgentId",
30077
30084
  "assigneeUserId",
30085
+ "nodeId",
30078
30086
  "checkedOutBy",
30079
30087
  "checkedOutAt",
30080
30088
  // `log` is fetched in slim mode so the server can aggregate
@@ -30174,6 +30182,7 @@ ${outcome}`;
30174
30182
  "sliceId",
30175
30183
  "assignedAgentId",
30176
30184
  "assigneeUserId",
30185
+ "nodeId",
30177
30186
  "checkedOutBy",
30178
30187
  "checkedOutAt"
30179
30188
  ];
@@ -30212,9 +30221,9 @@ ${outcome}`;
30212
30221
  dependencies, steps, log, attachments, steeringComments,
30213
30222
  comments, workflowStepResults, prInfo, issueInfo,
30214
30223
  sourceIssueProvider, sourceIssueRepository, sourceIssueExternalIssueId, sourceIssueNumber, sourceIssueUrl,
30215
- mergeDetails, breakIntoSubtasks, enabledWorkflowSteps, modifiedFiles, missionId, sliceId, assignedAgentId, assigneeUserId, checkedOutBy, checkedOutAt
30224
+ mergeDetails, breakIntoSubtasks, enabledWorkflowSteps, modifiedFiles, missionId, sliceId, assignedAgentId, assigneeUserId, nodeId, checkedOutBy, checkedOutAt
30216
30225
  ) VALUES (
30217
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
30226
+ ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
30218
30227
  )
30219
30228
  ON CONFLICT(id) DO UPDATE SET
30220
30229
  title = excluded.title,
@@ -30281,6 +30290,7 @@ ${outcome}`;
30281
30290
  sliceId = excluded.sliceId,
30282
30291
  assignedAgentId = excluded.assignedAgentId,
30283
30292
  assigneeUserId = excluded.assigneeUserId,
30293
+ nodeId = excluded.nodeId,
30284
30294
  checkedOutBy = excluded.checkedOutBy,
30285
30295
  checkedOutAt = excluded.checkedOutAt
30286
30296
  `).run(
@@ -30349,6 +30359,7 @@ ${outcome}`;
30349
30359
  task.sliceId ?? null,
30350
30360
  task.assignedAgentId ?? null,
30351
30361
  task.assigneeUserId ?? null,
30362
+ task.nodeId ?? null,
30352
30363
  task.checkedOutBy ?? null,
30353
30364
  task.checkedOutAt ?? null
30354
30365
  );
@@ -31111,6 +31122,7 @@ ${outcome}`;
31111
31122
  modelPresetId: input.modelPresetId,
31112
31123
  assignedAgentId: input.assignedAgentId,
31113
31124
  assigneeUserId: input.assigneeUserId,
31125
+ nodeId: input.nodeId,
31114
31126
  modelProvider: input.modelProvider,
31115
31127
  modelId: input.modelId,
31116
31128
  validatorModelProvider: input.validatorModelProvider,
@@ -31602,6 +31614,11 @@ ${newTask.description}
31602
31614
  } else if (updates.assigneeUserId !== void 0) {
31603
31615
  task.assigneeUserId = updates.assigneeUserId;
31604
31616
  }
31617
+ if (updates.nodeId === null) {
31618
+ task.nodeId = void 0;
31619
+ } else if (updates.nodeId !== void 0) {
31620
+ task.nodeId = updates.nodeId;
31621
+ }
31605
31622
  if (updates.checkedOutBy === null) {
31606
31623
  task.checkedOutBy = void 0;
31607
31624
  task.checkedOutAt = void 0;
@@ -34594,6 +34611,24 @@ var init_gh_cli = __esm({
34594
34611
  }
34595
34612
  });
34596
34613
 
34614
+ // ../core/src/settings-validation.ts
34615
+ function validateUnavailableNodePolicy(value) {
34616
+ if (value === void 0) {
34617
+ return void 0;
34618
+ }
34619
+ if (typeof value !== "string") {
34620
+ return void 0;
34621
+ }
34622
+ return UNAVAILABLE_NODE_POLICIES.includes(value) ? value : void 0;
34623
+ }
34624
+ var UNAVAILABLE_NODE_POLICIES;
34625
+ var init_settings_validation = __esm({
34626
+ "../core/src/settings-validation.ts"() {
34627
+ "use strict";
34628
+ UNAVAILABLE_NODE_POLICIES = ["block", "fallback-local"];
34629
+ }
34630
+ });
34631
+
34597
34632
  // ../core/src/routine.ts
34598
34633
  function isCronTrigger(trigger) {
34599
34634
  return trigger.type === "cron";
@@ -35175,27 +35210,27 @@ var init_plugin_loader = __esm({
35175
35210
  throw err;
35176
35211
  }
35177
35212
  }
35178
- resolvePluginPath(path) {
35179
- if (isAbsolute5(path)) {
35180
- return path;
35213
+ resolvePluginPath(path2) {
35214
+ if (isAbsolute5(path2)) {
35215
+ return path2;
35181
35216
  }
35182
- if (path.startsWith("@") || path.includes("/")) {
35183
- return resolve7(this.getProjectRoot(), path);
35217
+ if (path2.startsWith("@") || path2.includes("/")) {
35218
+ return resolve7(this.getProjectRoot(), path2);
35184
35219
  }
35185
- return resolve7(this.getProjectRoot(), path);
35220
+ return resolve7(this.getProjectRoot(), path2);
35186
35221
  }
35187
- async importPluginModule(path, bypassCache = false) {
35188
- if (!bypassCache && this.loadedModules.has(path)) {
35189
- return this.loadedModules.get(path);
35222
+ async importPluginModule(path2, bypassCache = false) {
35223
+ if (!bypassCache && this.loadedModules.has(path2)) {
35224
+ return this.loadedModules.get(path2);
35190
35225
  }
35191
- const moduleUrl = pathToFileURL(path).href;
35226
+ const moduleUrl = pathToFileURL(path2).href;
35192
35227
  let mod;
35193
35228
  if (bypassCache) {
35194
35229
  moduleImportVersion += 1;
35195
- const ext = extname(path);
35196
- const baseName = basename6(path, ext);
35197
- const reloadedPath = resolve7(dirname5(path), `.${baseName}.reload-${moduleImportVersion}${ext}`);
35198
- await copyFile(path, reloadedPath);
35230
+ const ext = extname(path2);
35231
+ const baseName = basename6(path2, ext);
35232
+ const reloadedPath = resolve7(dirname5(path2), `.${baseName}.reload-${moduleImportVersion}${ext}`);
35233
+ await copyFile(path2, reloadedPath);
35199
35234
  try {
35200
35235
  mod = await import(pathToFileURL(reloadedPath).href);
35201
35236
  } finally {
@@ -35204,16 +35239,16 @@ var init_plugin_loader = __esm({
35204
35239
  } else {
35205
35240
  mod = await import(moduleUrl);
35206
35241
  }
35207
- this.loadedModules.set(path, mod);
35242
+ this.loadedModules.set(path2, mod);
35208
35243
  return mod;
35209
35244
  }
35210
35245
  /**
35211
35246
  * Invalidate the module cache for a plugin path.
35212
35247
  * This ensures a fresh import when the plugin is loaded again.
35213
35248
  */
35214
- invalidateModuleCache(path) {
35215
- this.loadedModules.delete(path);
35216
- log.log(`Module cache invalidated for: ${path}`);
35249
+ invalidateModuleCache(path2) {
35250
+ this.loadedModules.delete(path2);
35251
+ log.log(`Module cache invalidated for: ${path2}`);
35217
35252
  }
35218
35253
  /**
35219
35254
  * Reload a plugin: stop the old instance, re-import, and start the new one.
@@ -37927,7 +37962,7 @@ var require_has_flag = __commonJS({
37927
37962
  var require_supports_color = __commonJS({
37928
37963
  "../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
37929
37964
  "use strict";
37930
- var os2 = __require("os");
37965
+ var os3 = __require("os");
37931
37966
  var tty = __require("tty");
37932
37967
  var hasFlag = require_has_flag();
37933
37968
  var { env } = process;
@@ -37975,7 +38010,7 @@ var require_supports_color = __commonJS({
37975
38010
  return min;
37976
38011
  }
37977
38012
  if (process.platform === "win32") {
37978
- const osRelease = os2.release().split(".");
38013
+ const osRelease = os3.release().split(".");
37979
38014
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
37980
38015
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
37981
38016
  }
@@ -39192,7 +39227,7 @@ var require_yauzl = __commonJS({
39192
39227
  exports.ZipFile = ZipFile;
39193
39228
  exports.Entry = Entry;
39194
39229
  exports.RandomAccessReader = RandomAccessReader;
39195
- function open(path, options, callback) {
39230
+ function open(path2, options, callback) {
39196
39231
  if (typeof options === "function") {
39197
39232
  callback = options;
39198
39233
  options = null;
@@ -39204,7 +39239,7 @@ var require_yauzl = __commonJS({
39204
39239
  if (options.validateEntrySizes == null) options.validateEntrySizes = true;
39205
39240
  if (options.strictFileNames == null) options.strictFileNames = false;
39206
39241
  if (callback == null) callback = defaultCallback;
39207
- fs.open(path, "r", function(err, fd) {
39242
+ fs.open(path2, "r", function(err, fd) {
39208
39243
  if (err) return callback(err);
39209
39244
  fromFd(fd, options, function(err2, zipfile) {
39210
39245
  if (err2) fs.close(fd, defaultCallback);
@@ -39807,7 +39842,7 @@ var require_extract_zip = __commonJS({
39807
39842
  var debug = require_src()("extract-zip");
39808
39843
  var { createWriteStream, promises: fs } = __require("fs");
39809
39844
  var getStream = require_get_stream();
39810
- var path = __require("path");
39845
+ var path2 = __require("path");
39811
39846
  var { promisify: promisify13 } = __require("util");
39812
39847
  var stream = __require("stream");
39813
39848
  var yauzl = require_yauzl();
@@ -39844,12 +39879,12 @@ var require_extract_zip = __commonJS({
39844
39879
  this.zipfile.readEntry();
39845
39880
  return;
39846
39881
  }
39847
- const destDir = path.dirname(path.join(this.opts.dir, entry.fileName));
39882
+ const destDir = path2.dirname(path2.join(this.opts.dir, entry.fileName));
39848
39883
  try {
39849
39884
  await fs.mkdir(destDir, { recursive: true });
39850
39885
  const canonicalDestDir = await fs.realpath(destDir);
39851
- const relativeDestDir = path.relative(this.opts.dir, canonicalDestDir);
39852
- if (relativeDestDir.split(path.sep).includes("..")) {
39886
+ const relativeDestDir = path2.relative(this.opts.dir, canonicalDestDir);
39887
+ if (relativeDestDir.split(path2.sep).includes("..")) {
39853
39888
  throw new Error(`Out of bound path "${canonicalDestDir}" found while processing file ${entry.fileName}`);
39854
39889
  }
39855
39890
  await this.extractEntry(entry);
@@ -39871,7 +39906,7 @@ var require_extract_zip = __commonJS({
39871
39906
  if (this.opts.onEntry) {
39872
39907
  this.opts.onEntry(entry, this.zipfile);
39873
39908
  }
39874
- const dest = path.join(this.opts.dir, entry.fileName);
39909
+ const dest = path2.join(this.opts.dir, entry.fileName);
39875
39910
  const mode = entry.externalFileAttributes >> 16 & 65535;
39876
39911
  const IFMT = 61440;
39877
39912
  const IFDIR = 16384;
@@ -39885,7 +39920,7 @@ var require_extract_zip = __commonJS({
39885
39920
  if (!isDir) isDir = madeBy === 0 && entry.externalFileAttributes === 16;
39886
39921
  debug("extracting entry", { filename: entry.fileName, isDir, isSymlink: symlink });
39887
39922
  const procMode = this.getExtractedMode(mode, isDir) & 511;
39888
- const destDir = isDir ? dest : path.dirname(dest);
39923
+ const destDir = isDir ? dest : path2.dirname(dest);
39889
39924
  const mkdirOptions = { recursive: true };
39890
39925
  if (isDir) {
39891
39926
  mkdirOptions.mode = procMode;
@@ -39927,7 +39962,7 @@ var require_extract_zip = __commonJS({
39927
39962
  };
39928
39963
  module.exports = async function(zipPath, opts) {
39929
39964
  debug("creating target directory", opts.dir);
39930
- if (!path.isAbsolute(opts.dir)) {
39965
+ if (!path2.isAbsolute(opts.dir)) {
39931
39966
  throw new Error("Target directory is expected to be absolute");
39932
39967
  }
39933
39968
  await fs.mkdir(opts.dir, { recursive: true });
@@ -40014,17 +40049,17 @@ var require_visit = __commonJS({
40014
40049
  visit.BREAK = BREAK;
40015
40050
  visit.SKIP = SKIP;
40016
40051
  visit.REMOVE = REMOVE;
40017
- function visit_(key, node, visitor, path) {
40018
- const ctrl = callVisitor(key, node, visitor, path);
40052
+ function visit_(key, node, visitor, path2) {
40053
+ const ctrl = callVisitor(key, node, visitor, path2);
40019
40054
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
40020
- replaceNode(key, path, ctrl);
40021
- return visit_(key, ctrl, visitor, path);
40055
+ replaceNode(key, path2, ctrl);
40056
+ return visit_(key, ctrl, visitor, path2);
40022
40057
  }
40023
40058
  if (typeof ctrl !== "symbol") {
40024
40059
  if (identity.isCollection(node)) {
40025
- path = Object.freeze(path.concat(node));
40060
+ path2 = Object.freeze(path2.concat(node));
40026
40061
  for (let i = 0; i < node.items.length; ++i) {
40027
- const ci = visit_(i, node.items[i], visitor, path);
40062
+ const ci = visit_(i, node.items[i], visitor, path2);
40028
40063
  if (typeof ci === "number")
40029
40064
  i = ci - 1;
40030
40065
  else if (ci === BREAK)
@@ -40035,13 +40070,13 @@ var require_visit = __commonJS({
40035
40070
  }
40036
40071
  }
40037
40072
  } else if (identity.isPair(node)) {
40038
- path = Object.freeze(path.concat(node));
40039
- const ck = visit_("key", node.key, visitor, path);
40073
+ path2 = Object.freeze(path2.concat(node));
40074
+ const ck = visit_("key", node.key, visitor, path2);
40040
40075
  if (ck === BREAK)
40041
40076
  return BREAK;
40042
40077
  else if (ck === REMOVE)
40043
40078
  node.key = null;
40044
- const cv = visit_("value", node.value, visitor, path);
40079
+ const cv = visit_("value", node.value, visitor, path2);
40045
40080
  if (cv === BREAK)
40046
40081
  return BREAK;
40047
40082
  else if (cv === REMOVE)
@@ -40062,17 +40097,17 @@ var require_visit = __commonJS({
40062
40097
  visitAsync.BREAK = BREAK;
40063
40098
  visitAsync.SKIP = SKIP;
40064
40099
  visitAsync.REMOVE = REMOVE;
40065
- async function visitAsync_(key, node, visitor, path) {
40066
- const ctrl = await callVisitor(key, node, visitor, path);
40100
+ async function visitAsync_(key, node, visitor, path2) {
40101
+ const ctrl = await callVisitor(key, node, visitor, path2);
40067
40102
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
40068
- replaceNode(key, path, ctrl);
40069
- return visitAsync_(key, ctrl, visitor, path);
40103
+ replaceNode(key, path2, ctrl);
40104
+ return visitAsync_(key, ctrl, visitor, path2);
40070
40105
  }
40071
40106
  if (typeof ctrl !== "symbol") {
40072
40107
  if (identity.isCollection(node)) {
40073
- path = Object.freeze(path.concat(node));
40108
+ path2 = Object.freeze(path2.concat(node));
40074
40109
  for (let i = 0; i < node.items.length; ++i) {
40075
- const ci = await visitAsync_(i, node.items[i], visitor, path);
40110
+ const ci = await visitAsync_(i, node.items[i], visitor, path2);
40076
40111
  if (typeof ci === "number")
40077
40112
  i = ci - 1;
40078
40113
  else if (ci === BREAK)
@@ -40083,13 +40118,13 @@ var require_visit = __commonJS({
40083
40118
  }
40084
40119
  }
40085
40120
  } else if (identity.isPair(node)) {
40086
- path = Object.freeze(path.concat(node));
40087
- const ck = await visitAsync_("key", node.key, visitor, path);
40121
+ path2 = Object.freeze(path2.concat(node));
40122
+ const ck = await visitAsync_("key", node.key, visitor, path2);
40088
40123
  if (ck === BREAK)
40089
40124
  return BREAK;
40090
40125
  else if (ck === REMOVE)
40091
40126
  node.key = null;
40092
- const cv = await visitAsync_("value", node.value, visitor, path);
40127
+ const cv = await visitAsync_("value", node.value, visitor, path2);
40093
40128
  if (cv === BREAK)
40094
40129
  return BREAK;
40095
40130
  else if (cv === REMOVE)
@@ -40116,23 +40151,23 @@ var require_visit = __commonJS({
40116
40151
  }
40117
40152
  return visitor;
40118
40153
  }
40119
- function callVisitor(key, node, visitor, path) {
40154
+ function callVisitor(key, node, visitor, path2) {
40120
40155
  if (typeof visitor === "function")
40121
- return visitor(key, node, path);
40156
+ return visitor(key, node, path2);
40122
40157
  if (identity.isMap(node))
40123
- return visitor.Map?.(key, node, path);
40158
+ return visitor.Map?.(key, node, path2);
40124
40159
  if (identity.isSeq(node))
40125
- return visitor.Seq?.(key, node, path);
40160
+ return visitor.Seq?.(key, node, path2);
40126
40161
  if (identity.isPair(node))
40127
- return visitor.Pair?.(key, node, path);
40162
+ return visitor.Pair?.(key, node, path2);
40128
40163
  if (identity.isScalar(node))
40129
- return visitor.Scalar?.(key, node, path);
40164
+ return visitor.Scalar?.(key, node, path2);
40130
40165
  if (identity.isAlias(node))
40131
- return visitor.Alias?.(key, node, path);
40166
+ return visitor.Alias?.(key, node, path2);
40132
40167
  return void 0;
40133
40168
  }
40134
- function replaceNode(key, path, node) {
40135
- const parent = path[path.length - 1];
40169
+ function replaceNode(key, path2, node) {
40170
+ const parent = path2[path2.length - 1];
40136
40171
  if (identity.isCollection(parent)) {
40137
40172
  parent.items[key] = node;
40138
40173
  } else if (identity.isPair(parent)) {
@@ -40740,10 +40775,10 @@ var require_Collection = __commonJS({
40740
40775
  var createNode = require_createNode();
40741
40776
  var identity = require_identity();
40742
40777
  var Node = require_Node();
40743
- function collectionFromPath(schema, path, value) {
40778
+ function collectionFromPath(schema, path2, value) {
40744
40779
  let v = value;
40745
- for (let i = path.length - 1; i >= 0; --i) {
40746
- const k = path[i];
40780
+ for (let i = path2.length - 1; i >= 0; --i) {
40781
+ const k = path2[i];
40747
40782
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
40748
40783
  const a = [];
40749
40784
  a[k] = v;
@@ -40762,7 +40797,7 @@ var require_Collection = __commonJS({
40762
40797
  sourceObjects: /* @__PURE__ */ new Map()
40763
40798
  });
40764
40799
  }
40765
- var isEmptyPath = (path) => path == null || typeof path === "object" && !!path[Symbol.iterator]().next().done;
40800
+ var isEmptyPath = (path2) => path2 == null || typeof path2 === "object" && !!path2[Symbol.iterator]().next().done;
40766
40801
  var Collection = class extends Node.NodeBase {
40767
40802
  constructor(type, schema) {
40768
40803
  super(type);
@@ -40792,11 +40827,11 @@ var require_Collection = __commonJS({
40792
40827
  * be a Pair instance or a `{ key, value }` object, which may not have a key
40793
40828
  * that already exists in the map.
40794
40829
  */
40795
- addIn(path, value) {
40796
- if (isEmptyPath(path))
40830
+ addIn(path2, value) {
40831
+ if (isEmptyPath(path2))
40797
40832
  this.add(value);
40798
40833
  else {
40799
- const [key, ...rest] = path;
40834
+ const [key, ...rest] = path2;
40800
40835
  const node = this.get(key, true);
40801
40836
  if (identity.isCollection(node))
40802
40837
  node.addIn(rest, value);
@@ -40810,8 +40845,8 @@ var require_Collection = __commonJS({
40810
40845
  * Removes a value from the collection.
40811
40846
  * @returns `true` if the item was found and removed.
40812
40847
  */
40813
- deleteIn(path) {
40814
- const [key, ...rest] = path;
40848
+ deleteIn(path2) {
40849
+ const [key, ...rest] = path2;
40815
40850
  if (rest.length === 0)
40816
40851
  return this.delete(key);
40817
40852
  const node = this.get(key, true);
@@ -40825,8 +40860,8 @@ var require_Collection = __commonJS({
40825
40860
  * scalar values from their surrounding node; to disable set `keepScalar` to
40826
40861
  * `true` (collections are always returned intact).
40827
40862
  */
40828
- getIn(path, keepScalar) {
40829
- const [key, ...rest] = path;
40863
+ getIn(path2, keepScalar) {
40864
+ const [key, ...rest] = path2;
40830
40865
  const node = this.get(key, true);
40831
40866
  if (rest.length === 0)
40832
40867
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -40844,8 +40879,8 @@ var require_Collection = __commonJS({
40844
40879
  /**
40845
40880
  * Checks if the collection includes a value with the key `key`.
40846
40881
  */
40847
- hasIn(path) {
40848
- const [key, ...rest] = path;
40882
+ hasIn(path2) {
40883
+ const [key, ...rest] = path2;
40849
40884
  if (rest.length === 0)
40850
40885
  return this.has(key);
40851
40886
  const node = this.get(key, true);
@@ -40855,8 +40890,8 @@ var require_Collection = __commonJS({
40855
40890
  * Sets a value in this collection. For `!!set`, `value` needs to be a
40856
40891
  * boolean to add/remove the item from the set.
40857
40892
  */
40858
- setIn(path, value) {
40859
- const [key, ...rest] = path;
40893
+ setIn(path2, value) {
40894
+ const [key, ...rest] = path2;
40860
40895
  if (rest.length === 0) {
40861
40896
  this.set(key, value);
40862
40897
  } else {
@@ -43368,9 +43403,9 @@ var require_Document = __commonJS({
43368
43403
  this.contents.add(value);
43369
43404
  }
43370
43405
  /** Adds a value to the document. */
43371
- addIn(path, value) {
43406
+ addIn(path2, value) {
43372
43407
  if (assertCollection(this.contents))
43373
- this.contents.addIn(path, value);
43408
+ this.contents.addIn(path2, value);
43374
43409
  }
43375
43410
  /**
43376
43411
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -43445,14 +43480,14 @@ var require_Document = __commonJS({
43445
43480
  * Removes a value from the document.
43446
43481
  * @returns `true` if the item was found and removed.
43447
43482
  */
43448
- deleteIn(path) {
43449
- if (Collection.isEmptyPath(path)) {
43483
+ deleteIn(path2) {
43484
+ if (Collection.isEmptyPath(path2)) {
43450
43485
  if (this.contents == null)
43451
43486
  return false;
43452
43487
  this.contents = null;
43453
43488
  return true;
43454
43489
  }
43455
- return assertCollection(this.contents) ? this.contents.deleteIn(path) : false;
43490
+ return assertCollection(this.contents) ? this.contents.deleteIn(path2) : false;
43456
43491
  }
43457
43492
  /**
43458
43493
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -43467,10 +43502,10 @@ var require_Document = __commonJS({
43467
43502
  * scalar values from their surrounding node; to disable set `keepScalar` to
43468
43503
  * `true` (collections are always returned intact).
43469
43504
  */
43470
- getIn(path, keepScalar) {
43471
- if (Collection.isEmptyPath(path))
43505
+ getIn(path2, keepScalar) {
43506
+ if (Collection.isEmptyPath(path2))
43472
43507
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
43473
- return identity.isCollection(this.contents) ? this.contents.getIn(path, keepScalar) : void 0;
43508
+ return identity.isCollection(this.contents) ? this.contents.getIn(path2, keepScalar) : void 0;
43474
43509
  }
43475
43510
  /**
43476
43511
  * Checks if the document includes a value with the key `key`.
@@ -43481,10 +43516,10 @@ var require_Document = __commonJS({
43481
43516
  /**
43482
43517
  * Checks if the document includes a value at `path`.
43483
43518
  */
43484
- hasIn(path) {
43485
- if (Collection.isEmptyPath(path))
43519
+ hasIn(path2) {
43520
+ if (Collection.isEmptyPath(path2))
43486
43521
  return this.contents !== void 0;
43487
- return identity.isCollection(this.contents) ? this.contents.hasIn(path) : false;
43522
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path2) : false;
43488
43523
  }
43489
43524
  /**
43490
43525
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -43501,13 +43536,13 @@ var require_Document = __commonJS({
43501
43536
  * Sets a value in this document. For `!!set`, `value` needs to be a
43502
43537
  * boolean to add/remove the item from the set.
43503
43538
  */
43504
- setIn(path, value) {
43505
- if (Collection.isEmptyPath(path)) {
43539
+ setIn(path2, value) {
43540
+ if (Collection.isEmptyPath(path2)) {
43506
43541
  this.contents = value;
43507
43542
  } else if (this.contents == null) {
43508
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path), value);
43543
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path2), value);
43509
43544
  } else if (assertCollection(this.contents)) {
43510
- this.contents.setIn(path, value);
43545
+ this.contents.setIn(path2, value);
43511
43546
  }
43512
43547
  }
43513
43548
  /**
@@ -45464,9 +45499,9 @@ var require_cst_visit = __commonJS({
45464
45499
  visit.BREAK = BREAK;
45465
45500
  visit.SKIP = SKIP;
45466
45501
  visit.REMOVE = REMOVE;
45467
- visit.itemAtPath = (cst, path) => {
45502
+ visit.itemAtPath = (cst, path2) => {
45468
45503
  let item = cst;
45469
- for (const [field, index] of path) {
45504
+ for (const [field, index] of path2) {
45470
45505
  const tok = item?.[field];
45471
45506
  if (tok && "items" in tok) {
45472
45507
  item = tok.items[index];
@@ -45475,23 +45510,23 @@ var require_cst_visit = __commonJS({
45475
45510
  }
45476
45511
  return item;
45477
45512
  };
45478
- visit.parentCollection = (cst, path) => {
45479
- const parent = visit.itemAtPath(cst, path.slice(0, -1));
45480
- const field = path[path.length - 1][0];
45513
+ visit.parentCollection = (cst, path2) => {
45514
+ const parent = visit.itemAtPath(cst, path2.slice(0, -1));
45515
+ const field = path2[path2.length - 1][0];
45481
45516
  const coll = parent?.[field];
45482
45517
  if (coll && "items" in coll)
45483
45518
  return coll;
45484
45519
  throw new Error("Parent collection not found");
45485
45520
  };
45486
- function _visit(path, item, visitor) {
45487
- let ctrl = visitor(item, path);
45521
+ function _visit(path2, item, visitor) {
45522
+ let ctrl = visitor(item, path2);
45488
45523
  if (typeof ctrl === "symbol")
45489
45524
  return ctrl;
45490
45525
  for (const field of ["key", "value"]) {
45491
45526
  const token = item[field];
45492
45527
  if (token && "items" in token) {
45493
45528
  for (let i = 0; i < token.items.length; ++i) {
45494
- const ci = _visit(Object.freeze(path.concat([[field, i]])), token.items[i], visitor);
45529
+ const ci = _visit(Object.freeze(path2.concat([[field, i]])), token.items[i], visitor);
45495
45530
  if (typeof ci === "number")
45496
45531
  i = ci - 1;
45497
45532
  else if (ci === BREAK)
@@ -45502,10 +45537,10 @@ var require_cst_visit = __commonJS({
45502
45537
  }
45503
45538
  }
45504
45539
  if (typeof ctrl === "function" && field === "key")
45505
- ctrl = ctrl(item, path);
45540
+ ctrl = ctrl(item, path2);
45506
45541
  }
45507
45542
  }
45508
- return typeof ctrl === "function" ? ctrl(item, path) : ctrl;
45543
+ return typeof ctrl === "function" ? ctrl(item, path2) : ctrl;
45509
45544
  }
45510
45545
  exports.visit = visit;
45511
45546
  }
@@ -48636,6 +48671,7 @@ __export(src_exports, {
48636
48671
  validateImportData: () => validateImportData,
48637
48672
  validateMessageMetadata: () => validateMessageMetadata,
48638
48673
  validatePluginManifest: () => validatePluginManifest,
48674
+ validateUnavailableNodePolicy: () => validateUnavailableNodePolicy,
48639
48675
  writeAgentMemoryFile: () => writeAgentMemoryFile,
48640
48676
  writeExportFile: () => writeExportFile,
48641
48677
  writeInsightsMemory: () => writeInsightsMemory,
@@ -48668,6 +48704,7 @@ var init_src = __esm({
48668
48704
  init_automation();
48669
48705
  init_automation_store();
48670
48706
  init_run_command();
48707
+ init_settings_validation();
48671
48708
  init_routine();
48672
48709
  init_routine_store();
48673
48710
  init_plugin_types();
@@ -49166,13 +49203,13 @@ async function searchAgentMemoryWithQmd(rootDir, agentMemory, query, limit) {
49166
49203
  return searchAgentMemoryFile(rootDir, agentMemory, query, limit);
49167
49204
  }
49168
49205
  }
49169
- function resolveAgentMemoryPath(rootDir, agentId, path) {
49206
+ function resolveAgentMemoryPath(rootDir, agentId, path2) {
49170
49207
  const safeAgentId = sanitizeAgentMemoryId(agentId);
49171
49208
  const prefix = `${AGENT_MEMORY_ROOT2}/${safeAgentId}/`;
49172
- if (!path.startsWith(prefix)) {
49209
+ if (!path2.startsWith(prefix)) {
49173
49210
  return null;
49174
49211
  }
49175
- const filename = path.slice(prefix.length);
49212
+ const filename = path2.slice(prefix.length);
49176
49213
  if (filename !== AGENT_MEMORY_FILENAME2 && filename !== AGENT_DREAMS_FILENAME2 && !DAILY_AGENT_MEMORY_RE2.test(filename)) {
49177
49214
  return null;
49178
49215
  }
@@ -49181,8 +49218,8 @@ function resolveAgentMemoryPath(rootDir, agentId, path) {
49181
49218
  displayPath: `${prefix}${filename}`
49182
49219
  };
49183
49220
  }
49184
- async function getAgentMemoryWindow(rootDir, agentMemory, path, startLine = 1, lineCount = 40) {
49185
- const resolved = resolveAgentMemoryPath(rootDir, agentMemory.agentId, path);
49221
+ async function getAgentMemoryWindow(rootDir, agentMemory, path2, startLine = 1, lineCount = 40) {
49222
+ const resolved = resolveAgentMemoryPath(rootDir, agentMemory.agentId, path2);
49186
49223
  if (!resolved) {
49187
49224
  return null;
49188
49225
  }
@@ -49908,12 +49945,12 @@ var init_concurrency = __esm({
49908
49945
  // ../engine/src/skill-resolver.ts
49909
49946
  import { existsSync as existsSync18, readFileSync as readFileSync4 } from "node:fs";
49910
49947
  import { join as join22 } from "node:path";
49911
- function readJsonObject(path) {
49912
- if (!existsSync18(path)) {
49948
+ function readJsonObject(path2) {
49949
+ if (!existsSync18(path2)) {
49913
49950
  return {};
49914
49951
  }
49915
49952
  try {
49916
- const parsed = JSON.parse(readFileSync4(path, "utf-8"));
49953
+ const parsed = JSON.parse(readFileSync4(path2, "utf-8"));
49917
49954
  return parsed && typeof parsed === "object" ? parsed : {};
49918
49955
  } catch {
49919
49956
  return {};
@@ -49973,17 +50010,17 @@ function resolveSessionSkills(context) {
49973
50010
  }
49974
50011
  const finalDecisions = /* @__PURE__ */ new Map();
49975
50012
  for (const pattern of skillPatterns) {
49976
- const path = normalizePattern(pattern);
50013
+ const path2 = normalizePattern(pattern);
49977
50014
  const isExclusion = isExclusionPattern(pattern);
49978
- finalDecisions.set(path, !isExclusion);
50015
+ finalDecisions.set(path2, !isExclusion);
49979
50016
  }
49980
50017
  const allowedSet = /* @__PURE__ */ new Set();
49981
50018
  const excludedSet = /* @__PURE__ */ new Set();
49982
- for (const [path, allowed] of finalDecisions) {
50019
+ for (const [path2, allowed] of finalDecisions) {
49983
50020
  if (allowed) {
49984
- allowedSet.add(path);
50021
+ allowedSet.add(path2);
49985
50022
  } else {
49986
- excludedSet.add(path);
50023
+ excludedSet.add(path2);
49987
50024
  }
49988
50025
  }
49989
50026
  const filterActive = hasPatterns || hasRequestedNames;
@@ -49991,11 +50028,11 @@ function resolveSessionSkills(context) {
49991
50028
  if (hasPatterns) {
49992
50029
  for (const pattern of skillPatterns) {
49993
50030
  if (!isExclusionPattern(pattern)) {
49994
- const path = normalizePattern(pattern);
50031
+ const path2 = normalizePattern(pattern);
49995
50032
  diagnostics8.push({
49996
50033
  type: "info",
49997
50034
  message: `Configured skill pattern: ${pattern}`,
49998
- skillPath: path
50035
+ skillPath: path2
49999
50036
  });
50000
50037
  }
50001
50038
  }
@@ -50522,12 +50559,12 @@ function isRetryableModelSelectionError(message) {
50522
50559
  const normalized = message.toLowerCase();
50523
50560
  return normalized.includes("rate limit") || normalized.includes("too many requests") || normalized.includes("429") || normalized.includes("401") || normalized.includes("403") || normalized.includes("unauthorized") || normalized.includes("forbidden") || normalized.includes("authentication") || normalized.includes("invalid api key") || normalized.includes("invalid key") || normalized.includes("api key") || normalized.includes("overloaded") || normalized.includes("quota") || normalized.includes("capacity") || normalized.includes("temporarily unavailable") || normalized.includes("invalid temperature");
50524
50561
  }
50525
- function readJsonObject2(path) {
50526
- if (!existsSync20(path)) {
50562
+ function readJsonObject2(path2) {
50563
+ if (!existsSync20(path2)) {
50527
50564
  return {};
50528
50565
  }
50529
50566
  try {
50530
- const parsed = JSON.parse(readFileSync6(path, "utf-8"));
50567
+ const parsed = JSON.parse(readFileSync6(path2, "utf-8"));
50531
50568
  return parsed && typeof parsed === "object" ? parsed : {};
50532
50569
  } catch {
50533
50570
  return {};
@@ -50704,8 +50741,8 @@ function resolveVendoredClaudeCliEntry() {
50704
50741
  if (!Array.isArray(extensions) || extensions.length === 0) return null;
50705
50742
  const entry = extensions[0];
50706
50743
  if (typeof entry !== "string" || entry.length === 0) return null;
50707
- const path = resolve10(dirname7(pkgJsonPath), entry);
50708
- return existsSync20(path) ? path : null;
50744
+ const path2 = resolve10(dirname7(pkgJsonPath), entry);
50745
+ return existsSync20(path2) ? path2 : null;
50709
50746
  } catch {
50710
50747
  return null;
50711
50748
  }
@@ -50730,8 +50767,8 @@ async function registerExtensionProviders(cwd, modelRegistry) {
50730
50767
  cwd,
50731
50768
  join24(resolvePiExtensionProjectRoot(cwd), ".fusion", "disabled-auto-extension-discovery")
50732
50769
  );
50733
- for (const { path, error } of extensionsResult.errors) {
50734
- extensionsLog.warn(`Failed to load ${path}: ${error}`);
50770
+ for (const { path: path2, error } of extensionsResult.errors) {
50771
+ extensionsLog.warn(`Failed to load ${path2}: ${error}`);
50735
50772
  }
50736
50773
  for (const { name, config, extensionPath } of extensionsResult.runtime.pendingProviderRegistrations) {
50737
50774
  try {
@@ -51560,8 +51597,8 @@ function trimAndClamp(value, maxLength, label, agentId) {
51560
51597
  log4.warn(`${label} exceeded max length for agent ${agentId}; truncating to ${maxLength} chars`);
51561
51598
  return trimmed.slice(0, maxLength);
51562
51599
  }
51563
- function isPathTraversal2(path) {
51564
- return path.split(/[\\/]+/).includes("..");
51600
+ function isPathTraversal2(path2) {
51601
+ return path2.split(/[\\/]+/).includes("..");
51565
51602
  }
51566
51603
  function resolveValidatedInstructionsPath(rawPath, rootDir, agentId) {
51567
51604
  const trimmed = rawPath.trim();
@@ -54282,10 +54319,11 @@ async function execWithProcessGroup(command, options) {
54282
54319
  ));
54283
54320
  return;
54284
54321
  }
54322
+ const useProcessGroup = process.platform !== "win32";
54285
54323
  const child = spawn2(command, {
54286
54324
  cwd: options.cwd,
54287
54325
  shell: true,
54288
- detached: true,
54326
+ detached: useProcessGroup,
54289
54327
  stdio: ["ignore", "pipe", "pipe"]
54290
54328
  });
54291
54329
  let stdout = "";
@@ -54298,7 +54336,11 @@ async function execWithProcessGroup(command, options) {
54298
54336
  const killTree = (sig) => {
54299
54337
  if (child.pid === void 0) return;
54300
54338
  try {
54301
- process.kill(-child.pid, sig);
54339
+ if (useProcessGroup) {
54340
+ process.kill(-child.pid, sig);
54341
+ } else {
54342
+ child.kill(sig);
54343
+ }
54302
54344
  } catch {
54303
54345
  }
54304
54346
  };
@@ -54489,18 +54531,18 @@ function truncateWorkflowScriptOutput(output) {
54489
54531
  return `... output truncated to last ${WORKFLOW_SCRIPT_OUTPUT_MAX_CHARS} characters ...
54490
54532
  ${output.slice(-WORKFLOW_SCRIPT_OUTPUT_MAX_CHARS)}`;
54491
54533
  }
54492
- function matchGlob(path, pattern) {
54534
+ function matchGlob(path2, pattern) {
54493
54535
  if (pattern.includes("**")) {
54494
54536
  const regexPattern2 = pattern.replace(/\./g, "\\.").replace(/\*\*/g, "<<<DOUBLESTAR>>>").replace(/\*/g, "[^/]*").replace(/<<<DOUBLESTAR>>>/g, ".*");
54495
54537
  const regex2 = new RegExp(`^${regexPattern2}$`);
54496
- return regex2.test(path);
54538
+ return regex2.test(path2);
54497
54539
  }
54498
54540
  const lastSlash = pattern.lastIndexOf("/");
54499
54541
  if (lastSlash !== -1) {
54500
54542
  const patternDir = pattern.slice(0, lastSlash);
54501
54543
  const patternFile = pattern.slice(lastSlash + 1);
54502
- const pathDir = path.lastIndexOf("/") !== -1 ? path.slice(0, path.lastIndexOf("/")) : "";
54503
- const pathFile = path.lastIndexOf("/") !== -1 ? path.slice(path.lastIndexOf("/")) : path;
54544
+ const pathDir = path2.lastIndexOf("/") !== -1 ? path2.slice(0, path2.lastIndexOf("/")) : "";
54545
+ const pathFile = path2.lastIndexOf("/") !== -1 ? path2.slice(path2.lastIndexOf("/")) : path2;
54504
54546
  if (patternDir.includes("*")) {
54505
54547
  const dirRegex = new RegExp(`^${patternDir.replace(/\./g, "\\.").replace(/\*/g, "[^/]*")}$`);
54506
54548
  if (!dirRegex.test(pathDir)) return false;
@@ -54509,10 +54551,10 @@ function matchGlob(path, pattern) {
54509
54551
  }
54510
54552
  return matchGlob(pathFile, patternFile);
54511
54553
  }
54512
- const fileName = path.lastIndexOf("/") !== -1 ? path.slice(path.lastIndexOf("/") + 1) : path;
54554
+ const fileName = path2.lastIndexOf("/") !== -1 ? path2.slice(path2.lastIndexOf("/") + 1) : path2;
54513
54555
  const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, "[^/]*");
54514
54556
  const regex = new RegExp(`^${regexPattern}$`);
54515
- return regex.test(fileName) || regex.test(path);
54557
+ return regex.test(fileName) || regex.test(path2);
54516
54558
  }
54517
54559
  async function getStagedFiles(cwd) {
54518
54560
  try {
@@ -54952,13 +54994,13 @@ async function amendMergeCommitWithFixes(rootDir, taskId, authorArg) {
54952
54994
  const match = line.match(/^:\d{6} 160000 [^\t]+\t(.+)$/);
54953
54995
  if (match) gitlinkPaths.push(match[1]);
54954
54996
  }
54955
- for (const path of gitlinkPaths) {
54956
- mergerLog.warn(`${taskId}: refusing to stage gitlink "${path}" (project uses no submodules \u2014 likely a nested worktree). Unstaging.`);
54997
+ for (const path2 of gitlinkPaths) {
54998
+ mergerLog.warn(`${taskId}: refusing to stage gitlink "${path2}" (project uses no submodules \u2014 likely a nested worktree). Unstaging.`);
54957
54999
  try {
54958
- await execAsync2(`git reset HEAD -- "${path}"`, { cwd: rootDir });
55000
+ await execAsync2(`git reset HEAD -- "${path2}"`, { cwd: rootDir });
54959
55001
  } catch (err) {
54960
55002
  const msg = err instanceof Error ? err.message : String(err);
54961
- mergerLog.warn(`${taskId}: failed to unstage gitlink "${path}": ${msg}`);
55003
+ mergerLog.warn(`${taskId}: failed to unstage gitlink "${path2}": ${msg}`);
54962
55004
  }
54963
55005
  }
54964
55006
  const { stdout: finalStaged } = await execAsync2("git diff --cached --name-only", {
@@ -57508,12 +57550,12 @@ var init_worktree_pool = __esm({
57508
57550
  * and prunes any stale entries.
57509
57551
  */
57510
57552
  acquire() {
57511
- for (const path of this.idle) {
57512
- this.idle.delete(path);
57513
- if (existsSync23(path)) {
57514
- return path;
57553
+ for (const path2 of this.idle) {
57554
+ this.idle.delete(path2);
57555
+ if (existsSync23(path2)) {
57556
+ return path2;
57515
57557
  }
57516
- worktreePoolLog.log(`Pruned stale entry: ${path}`);
57558
+ worktreePoolLog.log(`Pruned stale entry: ${path2}`);
57517
57559
  }
57518
57560
  return null;
57519
57561
  }
@@ -57533,8 +57575,8 @@ var init_worktree_pool = __esm({
57533
57575
  return this.idle.size;
57534
57576
  }
57535
57577
  /** Check whether a specific path is in the idle pool. */
57536
- has(path) {
57537
- return this.idle.has(path);
57578
+ has(path2) {
57579
+ return this.idle.has(path2);
57538
57580
  }
57539
57581
  /**
57540
57582
  * Remove and return all idle worktree paths.
@@ -57556,11 +57598,11 @@ var init_worktree_pool = __esm({
57556
57598
  * @param idlePaths — Absolute paths to idle worktree directories
57557
57599
  */
57558
57600
  rehydrate(idlePaths) {
57559
- for (const path of idlePaths) {
57560
- if (existsSync23(path)) {
57561
- this.idle.add(path);
57601
+ for (const path2 of idlePaths) {
57602
+ if (existsSync23(path2)) {
57603
+ this.idle.add(path2);
57562
57604
  } else {
57563
- worktreePoolLog.log(`Rehydrate skipped (not on disk): ${path}`);
57605
+ worktreePoolLog.log(`Rehydrate skipped (not on disk): ${path2}`);
57564
57606
  }
57565
57607
  }
57566
57608
  }
@@ -57725,14 +57767,14 @@ function extractPathsFromSection(section) {
57725
57767
  return paths;
57726
57768
  }
57727
57769
  function normalizePath(raw) {
57728
- let path = raw.trim();
57729
- if (path.endsWith("/*")) {
57730
- path = path.slice(0, -2);
57770
+ let path2 = raw.trim();
57771
+ if (path2.endsWith("/*")) {
57772
+ path2 = path2.slice(0, -2);
57731
57773
  }
57732
- if (path.endsWith("/")) {
57733
- path = path.slice(0, -1);
57774
+ if (path2.endsWith("/")) {
57775
+ path2 = path2.slice(0, -1);
57734
57776
  }
57735
- return path;
57777
+ return path2;
57736
57778
  }
57737
57779
  function buildConflictMatrix(stepScopes) {
57738
57780
  const indices = [...stepScopes.keys()].sort((a, b) => a - b);
@@ -58362,8 +58404,8 @@ var init_step_session_executor = __esm({
58362
58404
  const failedWorktreeSteps = /* @__PURE__ */ new Set();
58363
58405
  for (const stepIdx of wave.indices) {
58364
58406
  try {
58365
- const path = await this.createStepWorktree(stepIdx);
58366
- worktreePaths.set(stepIdx, path);
58407
+ const path2 = await this.createStepWorktree(stepIdx);
58408
+ worktreePaths.set(stepIdx, path2);
58367
58409
  } catch (err) {
58368
58410
  const errorMessage = err instanceof Error ? err.message : String(err);
58369
58411
  stepExecLog.error(
@@ -58382,8 +58424,8 @@ var init_step_session_executor = __esm({
58382
58424
  const parallelResults = [];
58383
58425
  if (parallelSteps.length > 0) {
58384
58426
  const promises = parallelSteps.map((stepIdx) => {
58385
- const path = worktreePaths.get(stepIdx) ?? this.options.worktreePath;
58386
- return this.executeStep(stepIdx, path);
58427
+ const path2 = worktreePaths.get(stepIdx) ?? this.options.worktreePath;
58428
+ return this.executeStep(stepIdx, path2);
58387
58429
  });
58388
58430
  const settled = await Promise.allSettled(promises);
58389
58431
  parallelResults.push(...settled.map((outcome, i) => {
@@ -61824,8 +61866,8 @@ Review the work done in this worktree and evaluate it against the criteria in yo
61824
61866
  * @param startPoint - Optional base branch/commit for new branch
61825
61867
  * @returns The actual worktree path (may differ if recovery generated new name)
61826
61868
  */
61827
- async createWorktree(branch, path, taskId, startPoint) {
61828
- const currentPath = path;
61869
+ async createWorktree(branch, path2, taskId, startPoint) {
61870
+ const currentPath = path2;
61829
61871
  let resolvedStartPoint;
61830
61872
  if (startPoint) {
61831
61873
  const resolved = await this.resolveWorktreeStartPoint(startPoint, taskId);
@@ -61885,58 +61927,58 @@ Review the work done in this worktree and evaluate it against the criteria in yo
61885
61927
  * Single attempt to create a worktree with conflict detection and recovery.
61886
61928
  * Returns the actual worktree path used (may differ from input if recovery generated new name).
61887
61929
  */
61888
- async tryCreateWorktree(branch, path, taskId, startPoint, attemptNumber = 0, recoveryDepth = 0) {
61889
- await this.assertWorktreePathNotNested(path, taskId);
61890
- if (existsSync25(path)) {
61891
- const isRegistered = await this.isRegisteredWorktree(path);
61930
+ async tryCreateWorktree(branch, path2, taskId, startPoint, attemptNumber = 0, recoveryDepth = 0) {
61931
+ await this.assertWorktreePathNotNested(path2, taskId);
61932
+ if (existsSync25(path2)) {
61933
+ const isRegistered = await this.isRegisteredWorktree(path2);
61892
61934
  if (!isRegistered) {
61893
61935
  await this.store.logEntry(
61894
61936
  taskId,
61895
- `Removing existing directory (not a registered worktree): ${path}`
61937
+ `Removing existing directory (not a registered worktree): ${path2}`
61896
61938
  );
61897
61939
  try {
61898
- await execAsync5(`rm -rf "${path}"`, { cwd: this.rootDir });
61940
+ await execAsync5(`rm -rf "${path2}"`, { cwd: this.rootDir });
61899
61941
  } catch (e) {
61900
61942
  const eMessage = e instanceof Error ? e.message : String(e);
61901
- throw new Error(`Failed to remove existing directory ${path}: ${eMessage}`);
61943
+ throw new Error(`Failed to remove existing directory ${path2}: ${eMessage}`);
61902
61944
  }
61903
61945
  } else {
61904
- executorLog.log(`Worktree already exists: ${path}`);
61905
- return { path, branch };
61946
+ executorLog.log(`Worktree already exists: ${path2}`);
61947
+ return { path: path2, branch };
61906
61948
  }
61907
61949
  }
61908
61950
  const createWithBranch = async (branchToCreate) => {
61909
- const cmd = startPoint ? `git worktree add -b "${branchToCreate}" "${path}" "${startPoint}"` : `git worktree add -b "${branchToCreate}" "${path}"`;
61951
+ const cmd = startPoint ? `git worktree add -b "${branchToCreate}" "${path2}" "${startPoint}"` : `git worktree add -b "${branchToCreate}" "${path2}"`;
61910
61952
  try {
61911
61953
  await execAsync5(cmd, { cwd: this.rootDir });
61912
61954
  } catch (err) {
61913
61955
  try {
61914
- await execAsync5(`rm -rf "${path}"`, { cwd: this.rootDir });
61956
+ await execAsync5(`rm -rf "${path2}"`, { cwd: this.rootDir });
61915
61957
  } catch {
61916
- executorLog.log(`Warning: failed to remove partial worktree directory after creation failure: ${path}`);
61958
+ executorLog.log(`Warning: failed to remove partial worktree directory after creation failure: ${path2}`);
61917
61959
  }
61918
61960
  throw err;
61919
61961
  }
61920
61962
  };
61921
61963
  const createFromExistingBranch = async () => {
61922
61964
  try {
61923
- await execAsync5(`git worktree add "${path}" "${branch}"`, { cwd: this.rootDir });
61965
+ await execAsync5(`git worktree add "${path2}" "${branch}"`, { cwd: this.rootDir });
61924
61966
  } catch (err) {
61925
61967
  try {
61926
- await execAsync5(`rm -rf "${path}"`, { cwd: this.rootDir });
61968
+ await execAsync5(`rm -rf "${path2}"`, { cwd: this.rootDir });
61927
61969
  } catch {
61928
- executorLog.log(`Warning: failed to remove partial worktree directory after creation failure: ${path}`);
61970
+ executorLog.log(`Warning: failed to remove partial worktree directory after creation failure: ${path2}`);
61929
61971
  }
61930
61972
  throw err;
61931
61973
  }
61932
61974
  };
61933
61975
  try {
61934
61976
  await createWithBranch(branch);
61935
- executorLog.log(`Worktree created: ${path}${startPoint ? ` (from ${startPoint})` : ""}`);
61977
+ executorLog.log(`Worktree created: ${path2}${startPoint ? ` (from ${startPoint})` : ""}`);
61936
61978
  if (attemptNumber > 0) {
61937
- await this.store.logEntry(taskId, `Worktree created on attempt ${attemptNumber + 1}`, path);
61979
+ await this.store.logEntry(taskId, `Worktree created on attempt ${attemptNumber + 1}`, path2);
61938
61980
  }
61939
- return { path, branch };
61981
+ return { path: path2, branch };
61940
61982
  } catch (initialError) {
61941
61983
  const conflictInfo = this.extractWorktreeConflictInfo(initialError);
61942
61984
  if (conflictInfo.type === "not-git-repo") {
@@ -61948,7 +61990,7 @@ Review the work done in this worktree and evaluate it against the criteria in yo
61948
61990
  const result = await this.handleWorktreeConflict(
61949
61991
  conflictInfo.path,
61950
61992
  branch,
61951
- path,
61993
+ path2,
61952
61994
  taskId,
61953
61995
  startPoint,
61954
61996
  attemptNumber
@@ -61969,7 +62011,7 @@ Review the work done in this worktree and evaluate it against the criteria in yo
61969
62011
  const branchCleaned = await this.cleanupStaleBranch(branch, taskId);
61970
62012
  if (branchCleaned) {
61971
62013
  await this.store.logEntry(taskId, `Removed stale branch reference, retrying`);
61972
- return this.tryCreateWorktree(branch, path, taskId, startPoint, attemptNumber, recoveryDepth + 1);
62014
+ return this.tryCreateWorktree(branch, path2, taskId, startPoint, attemptNumber, recoveryDepth + 1);
61973
62015
  }
61974
62016
  throw new Error(
61975
62017
  `Invalid reference for branch ${branch}: unable to clean up stale reference`
@@ -61977,13 +62019,13 @@ Review the work done in this worktree and evaluate it against the criteria in yo
61977
62019
  }
61978
62020
  if (conflictInfo.type === "leading-directories") {
61979
62021
  throw new Error(
61980
- `Cannot create worktree at ${path}: permission or path issue. Check that parent directories are writable.`
62022
+ `Cannot create worktree at ${path2}: permission or path issue. Check that parent directories are writable.`
61981
62023
  );
61982
62024
  }
61983
62025
  try {
61984
62026
  await createFromExistingBranch();
61985
- executorLog.log(`Worktree created from existing branch: ${path}`);
61986
- return { path, branch };
62027
+ executorLog.log(`Worktree created from existing branch: ${path2}`);
62028
+ return { path: path2, branch };
61987
62029
  } catch (fallbackError) {
61988
62030
  const fallbackErrorMessage = fallbackError instanceof Error ? fallbackError.message : String(fallbackError);
61989
62031
  const fallbackConflictInfo = this.extractWorktreeConflictInfo(fallbackError);
@@ -61996,7 +62038,7 @@ Review the work done in this worktree and evaluate it against the criteria in yo
61996
62038
  const result = await this.handleWorktreeConflict(
61997
62039
  fallbackConflictInfo.path,
61998
62040
  branch,
61999
- path,
62041
+ path2,
62000
62042
  taskId,
62001
62043
  startPoint,
62002
62044
  attemptNumber
@@ -62017,7 +62059,7 @@ Review the work done in this worktree and evaluate it against the criteria in yo
62017
62059
  const branchCleaned = await this.cleanupStaleBranch(branch, taskId);
62018
62060
  if (branchCleaned) {
62019
62061
  await this.store.logEntry(taskId, `Cleaned up stale reference in fallback, retrying`);
62020
- return this.tryCreateWorktree(branch, path, taskId, startPoint, attemptNumber, recoveryDepth + 1);
62062
+ return this.tryCreateWorktree(branch, path2, taskId, startPoint, attemptNumber, recoveryDepth + 1);
62021
62063
  }
62022
62064
  }
62023
62065
  throw new Error(`Failed to create worktree: ${fallbackErrorMessage}`);
@@ -62031,7 +62073,7 @@ Review the work done in this worktree and evaluate it against the criteria in yo
62031
62073
  *
62032
62074
  * @returns The worktree path if recovery succeeded, null if recovery failed
62033
62075
  */
62034
- async handleWorktreeConflict(conflictPath, branch, path, taskId, startPoint, attemptNumber) {
62076
+ async handleWorktreeConflict(conflictPath, branch, path2, taskId, startPoint, attemptNumber) {
62035
62077
  const shouldGenerateNewName = await this.shouldGenerateNewWorktreeName(
62036
62078
  conflictPath,
62037
62079
  taskId
@@ -62061,24 +62103,24 @@ Review the work done in this worktree and evaluate it against the criteria in yo
62061
62103
  }
62062
62104
  const cleanupSuccess = await this.cleanupConflictingWorktree(conflictPath, branch, taskId);
62063
62105
  if (cleanupSuccess) {
62064
- await this.store.logEntry(taskId, `Cleaned up conflicting worktree, retrying`, path);
62065
- return this.tryCreateWorktree(branch, path, taskId, startPoint, attemptNumber);
62106
+ await this.store.logEntry(taskId, `Cleaned up conflicting worktree, retrying`, path2);
62107
+ return this.tryCreateWorktree(branch, path2, taskId, startPoint, attemptNumber);
62066
62108
  }
62067
62109
  return null;
62068
62110
  }
62069
62111
  /**
62070
62112
  * Check if a path is registered as a git worktree.
62071
62113
  */
62072
- async isRegisteredWorktree(path) {
62073
- return isRegisteredGitWorktree2(this.rootDir, path);
62114
+ async isRegisteredWorktree(path2) {
62115
+ return isRegisteredGitWorktree2(this.rootDir, path2);
62074
62116
  }
62075
62117
  /**
62076
62118
  * Throw if `path` lies inside an existing registered worktree other than the
62077
62119
  * repo root. The repo root itself is a worktree (main branch) and must be
62078
62120
  * allowed — we only reject paths strictly *inside* a non-root worktree.
62079
62121
  */
62080
- async assertWorktreePathNotNested(path, taskId) {
62081
- const target = resolvePath(path);
62122
+ async assertWorktreePathNotNested(path2, taskId) {
62123
+ const target = resolvePath(path2);
62082
62124
  const rootResolved = resolvePath(this.rootDir);
62083
62125
  const registered = await getRegisteredWorktreePaths(this.rootDir);
62084
62126
  for (const wt of registered) {
@@ -62716,11 +62758,11 @@ function pathsOverlap2(a, b) {
62716
62758
  }
62717
62759
  return false;
62718
62760
  }
62719
- function normalizeOverlapPath(path) {
62720
- return path.trim().replaceAll("\\", "/").replace(/^\.\//, "");
62761
+ function normalizeOverlapPath(path2) {
62762
+ return path2.trim().replaceAll("\\", "/").replace(/^\.\//, "");
62721
62763
  }
62722
- function isIgnoredOverlapPath(path, ignorePath) {
62723
- const normalizedPath = normalizeOverlapPath(path);
62764
+ function isIgnoredOverlapPath(path2, ignorePath) {
62765
+ const normalizedPath = normalizeOverlapPath(path2);
62724
62766
  const normalizedIgnore = normalizeOverlapPath(ignorePath);
62725
62767
  if (normalizedIgnore.endsWith("/*")) {
62726
62768
  const directory = normalizedIgnore.slice(0, -2);
@@ -62740,7 +62782,7 @@ function filterPathsByIgnoreList(paths, ignorePaths) {
62740
62782
  if (normalizedIgnorePaths.length === 0) {
62741
62783
  return paths;
62742
62784
  }
62743
- return paths.filter((path) => !normalizedIgnorePaths.some((ignore) => isIgnoredOverlapPath(path, ignore)));
62785
+ return paths.filter((path2) => !normalizedIgnorePaths.some((ignore) => isIgnoredOverlapPath(path2, ignore)));
62744
62786
  }
62745
62787
  var Scheduler;
62746
62788
  var init_scheduler = __esm({
@@ -70041,18 +70083,18 @@ var init_self_healing = __esm({
70041
70083
  const registered = await getRegisteredWorktreePaths(this.options.rootDir);
70042
70084
  const unregistered = dirs.filter((d) => !registered.has(resolve14(d)));
70043
70085
  let cleaned = 0;
70044
- for (const path of unregistered) {
70045
- const rel = relative7(worktreesDir, path);
70086
+ for (const path2 of unregistered) {
70087
+ const rel = relative7(worktreesDir, path2);
70046
70088
  if (rel === "" || rel.startsWith("..") || isAbsolute11(rel)) {
70047
- log8.warn(`Refusing to remove path outside .worktrees: ${path}`);
70089
+ log8.warn(`Refusing to remove path outside .worktrees: ${path2}`);
70048
70090
  continue;
70049
70091
  }
70050
70092
  try {
70051
- rmSync3(path, { recursive: true, force: true });
70052
- log8.log(`Cleaned unregistered worktree dir: ${path}`);
70093
+ rmSync3(path2, { recursive: true, force: true });
70094
+ log8.log(`Cleaned unregistered worktree dir: ${path2}`);
70053
70095
  cleaned++;
70054
70096
  } catch (err) {
70055
- log8.warn(`Failed to remove unregistered worktree dir ${path}: ${err instanceof Error ? err.message : String(err)}`);
70097
+ log8.warn(`Failed to remove unregistered worktree dir ${path2}: ${err instanceof Error ? err.message : String(err)}`);
70056
70098
  }
70057
70099
  }
70058
70100
  if (cleaned > 0) {
@@ -72266,9 +72308,9 @@ var init_remote_node_client = __esm({
72266
72308
  }
72267
72309
  }
72268
72310
  }
72269
- const path = query.toString().length > 0 ? `/api/tasks?${query.toString()}` : "/api/tasks";
72311
+ const path2 = query.toString().length > 0 ? `/api/tasks?${query.toString()}` : "/api/tasks";
72270
72312
  return this.withRetry(
72271
- () => this.requestJson(path, {
72313
+ () => this.requestJson(path2, {
72272
72314
  method: "GET"
72273
72315
  })
72274
72316
  );
@@ -72309,8 +72351,8 @@ var init_remote_node_client = __esm({
72309
72351
  }
72310
72352
  yield* this.parseJsonLines(response.body, options?.signal);
72311
72353
  }
72312
- async requestJson(path, init) {
72313
- const response = await this.fetchWithTimeout(path, {
72354
+ async requestJson(path2, init) {
72355
+ const response = await this.fetchWithTimeout(path2, {
72314
72356
  ...init,
72315
72357
  headers: {
72316
72358
  ...this.getAuthHeaders(),
@@ -72320,20 +72362,20 @@ var init_remote_node_client = __esm({
72320
72362
  }
72321
72363
  });
72322
72364
  if (!response.ok) {
72323
- await this.throwHttpError(path, response);
72365
+ await this.throwHttpError(path2, response);
72324
72366
  }
72325
72367
  try {
72326
72368
  return await response.json();
72327
72369
  } catch (error) {
72328
72370
  throw new RemoteNodeRequestError(
72329
- `Failed to parse JSON response for ${path}: ${error instanceof Error ? error.message : String(error)}`,
72371
+ `Failed to parse JSON response for ${path2}: ${error instanceof Error ? error.message : String(error)}`,
72330
72372
  false
72331
72373
  );
72332
72374
  }
72333
72375
  }
72334
- async openStream(path, signal) {
72376
+ async openStream(path2, signal) {
72335
72377
  const response = await this.fetchWithTimeout(
72336
- path,
72378
+ path2,
72337
72379
  {
72338
72380
  method: "GET",
72339
72381
  headers: {
@@ -72344,16 +72386,16 @@ var init_remote_node_client = __esm({
72344
72386
  signal
72345
72387
  );
72346
72388
  if (!response.ok) {
72347
- await this.throwHttpError(path, response);
72389
+ await this.throwHttpError(path2, response);
72348
72390
  }
72349
72391
  return response;
72350
72392
  }
72351
- async throwHttpError(path, response) {
72393
+ async throwHttpError(path2, response) {
72352
72394
  const responseBody = (await response.text()).trim();
72353
72395
  const snippet = responseBody.length > 0 ? ` \u2014 ${responseBody.slice(0, 300)}` : "";
72354
72396
  const retryable = response.status >= 500;
72355
72397
  throw new RemoteNodeRequestError(
72356
- `Remote node request failed (${response.status} ${response.statusText}) for ${path}${snippet}`,
72398
+ `Remote node request failed (${response.status} ${response.statusText}) for ${path2}${snippet}`,
72357
72399
  retryable,
72358
72400
  response.status
72359
72401
  );
@@ -72363,7 +72405,7 @@ var init_remote_node_client = __esm({
72363
72405
  Authorization: `Bearer ${this.apiKey}`
72364
72406
  };
72365
72407
  }
72366
- async fetchWithTimeout(path, init, externalSignal) {
72408
+ async fetchWithTimeout(path2, init, externalSignal) {
72367
72409
  const controller = new AbortController();
72368
72410
  let timedOut = false;
72369
72411
  const timeout = setTimeout(() => {
@@ -72379,7 +72421,7 @@ var init_remote_node_client = __esm({
72379
72421
  externalSignal.addEventListener("abort", onAbort, { once: true });
72380
72422
  }
72381
72423
  try {
72382
- return await fetch(`${this.baseUrl}${path}`, {
72424
+ return await fetch(`${this.baseUrl}${path2}`, {
72383
72425
  ...init,
72384
72426
  signal: controller.signal
72385
72427
  });
@@ -72389,15 +72431,15 @@ var init_remote_node_client = __esm({
72389
72431
  }
72390
72432
  if (timedOut) {
72391
72433
  throw new RemoteNodeRequestError(
72392
- `Remote node request timed out after ${this.timeoutMs}ms (${path})`,
72434
+ `Remote node request timed out after ${this.timeoutMs}ms (${path2})`,
72393
72435
  true
72394
72436
  );
72395
72437
  }
72396
72438
  if (error instanceof Error && error.name === "AbortError") {
72397
- throw new RemoteNodeRequestError(`Remote node request aborted (${path})`, false);
72439
+ throw new RemoteNodeRequestError(`Remote node request aborted (${path2})`, false);
72398
72440
  }
72399
72441
  throw new RemoteNodeRequestError(
72400
- `Remote node network error (${path}): ${error instanceof Error ? error.message : String(error)}`,
72442
+ `Remote node network error (${path2}): ${error instanceof Error ? error.message : String(error)}`,
72401
72443
  true
72402
72444
  );
72403
72445
  } finally {
@@ -77350,166 +77392,882 @@ var init_plugin_routes = __esm({
77350
77392
  }
77351
77393
  });
77352
77394
 
77353
- // ../dashboard/src/project-store-resolver.ts
77354
- var init_project_store_resolver = __esm({
77355
- "../dashboard/src/project-store-resolver.ts"() {
77395
+ // ../plugin-sdk/src/index.ts
77396
+ function definePlugin(plugin4) {
77397
+ return plugin4;
77398
+ }
77399
+ var init_src3 = __esm({
77400
+ "../plugin-sdk/src/index.ts"() {
77356
77401
  "use strict";
77402
+ init_src();
77357
77403
  }
77358
77404
  });
77359
77405
 
77360
- // ../dashboard/src/routes/context.ts
77361
- import { Router as Router2 } from "express";
77362
- var init_context = __esm({
77363
- "../dashboard/src/routes/context.ts"() {
77364
- "use strict";
77365
- init_api_error();
77366
- init_project_store_resolver();
77367
- init_runtime_logger();
77406
+ // ../../plugins/fusion-plugin-hermes-runtime/dist/cli-spawn.js
77407
+ import { spawn as spawn4, spawnSync } from "node:child_process";
77408
+ import os2 from "node:os";
77409
+ import path, { sep as PATH_SEP } from "node:path";
77410
+ function resolveBinaryForSpawn(binary) {
77411
+ if (process.platform !== "win32")
77412
+ return binary;
77413
+ if (binary.includes(PATH_SEP) || binary.includes("/") || /\.[a-z]{2,4}$/i.test(binary)) {
77414
+ return binary;
77368
77415
  }
77369
- });
77370
-
77371
- // ../dashboard/src/routes/register-task-workflow-routes.ts
77372
- var init_register_task_workflow_routes = __esm({
77373
- "../dashboard/src/routes/register-task-workflow-routes.ts"() {
77374
- "use strict";
77375
- init_src();
77376
- init_api_error();
77416
+ const cached = resolvedBinaryCache.get(binary);
77417
+ if (cached)
77418
+ return cached;
77419
+ try {
77420
+ const result = spawnSync("where", [binary], { encoding: "utf-8" });
77421
+ if (result.status === 0) {
77422
+ const first = (result.stdout ?? "").trim().split(/\r?\n/)[0];
77423
+ if (first?.length) {
77424
+ resolvedBinaryCache.set(binary, first);
77425
+ return first;
77426
+ }
77427
+ }
77428
+ } catch {
77377
77429
  }
77378
- });
77379
-
77380
- // ../dashboard/src/routes/register-planning-subtask-routes.ts
77381
- var init_register_planning_subtask_routes = __esm({
77382
- "../dashboard/src/routes/register-planning-subtask-routes.ts"() {
77383
- "use strict";
77384
- init_api_error();
77385
- init_sse_buffer();
77430
+ return binary;
77431
+ }
77432
+ function hermesProfileHome(profileName) {
77433
+ const base = process.env.HERMES_HOME ?? path.join(os2.homedir(), ".hermes");
77434
+ if (profileName === "default" || profileName === "")
77435
+ return base;
77436
+ return path.join(base, "profiles", profileName);
77437
+ }
77438
+ function resolveCliSettings(settings) {
77439
+ const str = (v) => typeof v === "string" && v.trim().length > 0 ? v.trim() : void 0;
77440
+ const num = (v, envKey, fallback) => {
77441
+ if (typeof v === "number" && Number.isFinite(v) && v > 0)
77442
+ return v;
77443
+ const raw = str(v) ?? str(process.env[envKey]);
77444
+ if (raw !== void 0) {
77445
+ const parsed = Number(raw);
77446
+ if (Number.isFinite(parsed) && parsed > 0)
77447
+ return parsed;
77448
+ }
77449
+ return fallback;
77450
+ };
77451
+ const bool = (v, envKey, fallback) => {
77452
+ if (typeof v === "boolean")
77453
+ return v;
77454
+ const raw = str(v) ?? str(process.env[envKey]);
77455
+ if (raw !== void 0)
77456
+ return raw === "1" || raw.toLowerCase() === "true";
77457
+ return fallback;
77458
+ };
77459
+ return {
77460
+ binaryPath: str(settings?.binaryPath) ?? str(process.env.HERMES_BIN) ?? "hermes",
77461
+ model: str(settings?.model) ?? str(process.env.HERMES_MODEL_ID),
77462
+ provider: str(settings?.provider) ?? str(process.env.HERMES_PROVIDER),
77463
+ maxTurns: num(settings?.maxTurns, "HERMES_MAX_TURNS", 12),
77464
+ yolo: bool(settings?.yolo, "HERMES_YOLO", false),
77465
+ cliTimeoutMs: num(settings?.cliTimeoutMs, "HERMES_CLI_TIMEOUT_MS", 3e5),
77466
+ profile: str(settings?.profile) ?? str(process.env.HERMES_PROFILE)
77467
+ };
77468
+ }
77469
+ function cleanText(raw) {
77470
+ return raw.replace(ANSI_RE, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
77471
+ }
77472
+ function stripChrome(text) {
77473
+ const lines = text.split("\n");
77474
+ const filtered = lines.filter((line) => !CHROME_LINE_RES.some((re) => re.test(line)));
77475
+ return filtered.join("\n").trim();
77476
+ }
77477
+ function parseHermesOutput(rawStdout, rawStderr) {
77478
+ const cleaned = cleanText(rawStdout);
77479
+ const match = SESSION_ID_RE.exec(cleaned);
77480
+ if (!match) {
77481
+ const combined = [rawStdout, rawStderr].filter(Boolean).join("\n");
77482
+ throw new Error(`hermes: missing session_id in output.
77483
+ ${combined}`);
77386
77484
  }
77387
- });
77388
-
77389
- // ../dashboard/src/rate-limit.ts
77390
- var init_rate_limit = __esm({
77391
- "../dashboard/src/rate-limit.ts"() {
77392
- "use strict";
77393
- init_api_error();
77485
+ const sessionId = match[1];
77486
+ const sessionIdLineStart = cleaned.lastIndexOf("\nsession_id:");
77487
+ const bodyRaw = sessionIdLineStart >= 0 ? cleaned.slice(0, sessionIdLineStart) : cleaned;
77488
+ const body = stripChrome(bodyRaw);
77489
+ return { body, sessionId };
77490
+ }
77491
+ function buildHermesArgs(prompt, settings, resumeSessionId) {
77492
+ const args = ["chat", "-q", prompt, "-Q", "--source", "tool"];
77493
+ if (resumeSessionId) {
77494
+ args.push("--resume", resumeSessionId);
77394
77495
  }
77395
- });
77396
-
77397
- // ../dashboard/src/routes/register-chat-routes.ts
77398
- var init_register_chat_routes = __esm({
77399
- "../dashboard/src/routes/register-chat-routes.ts"() {
77400
- "use strict";
77401
- init_api_error();
77402
- init_rate_limit();
77403
- init_sse_buffer();
77496
+ if (settings.model) {
77497
+ args.push("-m", settings.model);
77404
77498
  }
77405
- });
77406
-
77407
- // ../dashboard/src/remote-auth.ts
77408
- var init_remote_auth = __esm({
77409
- "../dashboard/src/remote-auth.ts"() {
77499
+ if (settings.provider) {
77500
+ args.push("--provider", settings.provider);
77501
+ }
77502
+ args.push("--max-turns", String(settings.maxTurns));
77503
+ if (settings.yolo) {
77504
+ args.push("--yolo");
77505
+ }
77506
+ return args;
77507
+ }
77508
+ async function invokeHermesCli(prompt, settings, resumeSessionId, signal) {
77509
+ const args = buildHermesArgs(prompt, settings, resumeSessionId);
77510
+ const binary = resolveBinaryForSpawn(settings.binaryPath);
77511
+ return new Promise((resolve17, reject) => {
77512
+ let settled = false;
77513
+ const spawnEnv = { ...process.env, PYTHONUNBUFFERED: "1" };
77514
+ if (settings.profile) {
77515
+ spawnEnv.HERMES_HOME = hermesProfileHome(settings.profile);
77516
+ }
77517
+ const child = spawn4(binary, args, {
77518
+ stdio: ["ignore", "pipe", "pipe"],
77519
+ env: spawnEnv
77520
+ });
77521
+ const hardKillTimer = setTimeout(() => {
77522
+ if (settled)
77523
+ return;
77524
+ settled = true;
77525
+ try {
77526
+ child.kill("SIGKILL");
77527
+ } catch {
77528
+ }
77529
+ reject(new Error(`hermes: process timed out after ${settings.cliTimeoutMs}ms`));
77530
+ }, settings.cliTimeoutMs);
77531
+ const onAbort = () => {
77532
+ if (settled)
77533
+ return;
77534
+ settled = true;
77535
+ clearTimeout(hardKillTimer);
77536
+ try {
77537
+ child.kill("SIGTERM");
77538
+ } catch {
77539
+ }
77540
+ reject(new Error("hermes: invocation aborted"));
77541
+ };
77542
+ if (signal) {
77543
+ if (signal.aborted) {
77544
+ onAbort();
77545
+ return;
77546
+ }
77547
+ signal.addEventListener("abort", onAbort, { once: true });
77548
+ }
77549
+ let stdout = "";
77550
+ let stderr = "";
77551
+ child.stdout?.on("data", (chunk) => {
77552
+ stdout += chunk.toString("utf-8");
77553
+ });
77554
+ child.stderr?.on("data", (chunk) => {
77555
+ stderr += chunk.toString("utf-8");
77556
+ });
77557
+ child.on("error", (err) => {
77558
+ if (settled)
77559
+ return;
77560
+ settled = true;
77561
+ clearTimeout(hardKillTimer);
77562
+ signal?.removeEventListener("abort", onAbort);
77563
+ const isNotFound = err.code === "ENOENT";
77564
+ reject(new Error(isNotFound ? `hermes: binary not found at "${settings.binaryPath}". Install hermes or set binaryPath/HERMES_BIN.` : `hermes: spawn error \u2014 ${err.message}`));
77565
+ });
77566
+ child.on("close", (code) => {
77567
+ if (settled)
77568
+ return;
77569
+ settled = true;
77570
+ clearTimeout(hardKillTimer);
77571
+ signal?.removeEventListener("abort", onAbort);
77572
+ if (code !== 0) {
77573
+ const combined = [stdout, stderr].filter(Boolean).join("\n");
77574
+ reject(new Error(`hermes: process exited with code ${String(code)}.
77575
+ ${combined}`));
77576
+ return;
77577
+ }
77578
+ try {
77579
+ resolve17(parseHermesOutput(stdout, stderr));
77580
+ } catch (parseErr) {
77581
+ reject(parseErr);
77582
+ }
77583
+ });
77584
+ });
77585
+ }
77586
+ var resolvedBinaryCache, ANSI_RE, SESSION_ID_RE, CHROME_LINE_RES;
77587
+ var init_cli_spawn = __esm({
77588
+ "../../plugins/fusion-plugin-hermes-runtime/dist/cli-spawn.js"() {
77410
77589
  "use strict";
77590
+ resolvedBinaryCache = /* @__PURE__ */ new Map();
77591
+ ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]/g;
77592
+ SESSION_ID_RE = /^session_id:\s+([0-9]{8}_[0-9]{6}_[0-9a-f]{6})\s*$/m;
77593
+ CHROME_LINE_RES = [
77594
+ /^\s*┊\s/,
77595
+ // memory/status sidebar lines
77596
+ /^↻ Resumed session /,
77597
+ // resume banner
77598
+ /^╭─.*╮\s*$/,
77599
+ // top box border
77600
+ /^╰─.*╯\s*$/,
77601
+ // bottom box border
77602
+ /^Query:\s*/
77603
+ // query echo line
77604
+ ];
77411
77605
  }
77412
77606
  });
77413
77607
 
77414
- // ../dashboard/src/routes/register-settings-memory-routes.ts
77415
- var init_register_settings_memory_routes = __esm({
77416
- "../dashboard/src/routes/register-settings-memory-routes.ts"() {
77608
+ // ../../plugins/fusion-plugin-hermes-runtime/dist/runtime-adapter.js
77609
+ var HermesRuntimeAdapter;
77610
+ var init_runtime_adapter = __esm({
77611
+ "../../plugins/fusion-plugin-hermes-runtime/dist/runtime-adapter.js"() {
77417
77612
  "use strict";
77418
- init_src();
77419
- init_api_error();
77420
- init_remote_auth();
77421
- init_project_store_resolver();
77613
+ init_cli_spawn();
77614
+ HermesRuntimeAdapter = class {
77615
+ id = "hermes";
77616
+ name = "Hermes Runtime";
77617
+ settings;
77618
+ constructor(settings) {
77619
+ this.settings = resolveCliSettings(settings);
77620
+ }
77621
+ async createSession(options) {
77622
+ const session = {
77623
+ model: void 0,
77624
+ systemPrompt: options.systemPrompt,
77625
+ messages: [],
77626
+ apiKey: void 0,
77627
+ thinkingLevel: void 0,
77628
+ sessionId: "",
77629
+ lastModelDescription: this.describeFromSettings(),
77630
+ callbacks: {
77631
+ onText: options.onText,
77632
+ onThinking: options.onThinking,
77633
+ onToolStart: options.onToolStart,
77634
+ onToolEnd: options.onToolEnd
77635
+ },
77636
+ dispose: () => void 0
77637
+ };
77638
+ return { session, sessionFile: void 0 };
77639
+ }
77640
+ async promptWithFallback(session, prompt, _options) {
77641
+ const resumeId = session.sessionId || void 0;
77642
+ const result = await invokeHermesCli(prompt, this.settings, resumeId);
77643
+ session.sessionId = result.sessionId;
77644
+ session.lastModelDescription = this.describeFromSettings();
77645
+ if (result.body) {
77646
+ session.callbacks.onText?.(result.body);
77647
+ }
77648
+ }
77649
+ describeModel(session) {
77650
+ return session.lastModelDescription || this.describeFromSettings();
77651
+ }
77652
+ async dispose(_session) {
77653
+ }
77654
+ describeFromSettings() {
77655
+ const provider = this.settings.provider;
77656
+ const model = this.settings.model;
77657
+ if (provider && model)
77658
+ return `hermes/${provider}/${model}`;
77659
+ if (model)
77660
+ return `hermes/${model}`;
77661
+ if (provider)
77662
+ return `hermes/${provider}`;
77663
+ return "hermes";
77664
+ }
77665
+ };
77422
77666
  }
77423
77667
  });
77424
77668
 
77425
- // ../dashboard/src/terminal-service.ts
77426
- import { createRequire as createRequire3 } from "node:module";
77427
- var isBunBinary, require2;
77428
- var init_terminal_service = __esm({
77429
- "../dashboard/src/terminal-service.ts"() {
77669
+ // ../../plugins/fusion-plugin-hermes-runtime/dist/probe.js
77670
+ var init_probe = __esm({
77671
+ "../../plugins/fusion-plugin-hermes-runtime/dist/probe.js"() {
77430
77672
  "use strict";
77431
- isBunBinary = typeof Bun !== "undefined" && !!Bun.embeddedFiles;
77432
- require2 = createRequire3(import.meta.url);
77433
77673
  }
77434
77674
  });
77435
77675
 
77436
- // ../dashboard/src/routes/register-messaging-scripts.ts
77437
- var init_register_messaging_scripts = __esm({
77438
- "../dashboard/src/routes/register-messaging-scripts.ts"() {
77676
+ // ../../plugins/fusion-plugin-hermes-runtime/dist/index.js
77677
+ var HERMES_RUNTIME_ID, HERMES_RUNTIME_VERSION, hermesRuntimeMetadata, hermesRuntimeFactory, plugin;
77678
+ var init_dist = __esm({
77679
+ "../../plugins/fusion-plugin-hermes-runtime/dist/index.js"() {
77439
77680
  "use strict";
77440
- init_src();
77441
- init_api_error();
77442
- init_terminal_service();
77681
+ init_src3();
77682
+ init_cli_spawn();
77683
+ init_runtime_adapter();
77684
+ init_runtime_adapter();
77685
+ init_cli_spawn();
77686
+ init_probe();
77687
+ HERMES_RUNTIME_ID = "hermes";
77688
+ HERMES_RUNTIME_VERSION = "0.2.0";
77689
+ hermesRuntimeMetadata = {
77690
+ runtimeId: HERMES_RUNTIME_ID,
77691
+ name: "Hermes Runtime",
77692
+ description: "Drives the local `hermes` CLI (NousResearch/hermes-agent)",
77693
+ version: HERMES_RUNTIME_VERSION
77694
+ };
77695
+ hermesRuntimeFactory = async (ctx) => {
77696
+ return new HermesRuntimeAdapter(ctx.settings);
77697
+ };
77698
+ plugin = definePlugin({
77699
+ manifest: {
77700
+ id: "fusion-plugin-hermes-runtime",
77701
+ name: "Hermes Runtime Plugin",
77702
+ version: HERMES_RUNTIME_VERSION,
77703
+ description: "Drives the local `hermes` CLI for Fusion agents \u2014 captures session ids and resumes via --resume.",
77704
+ author: "Fusion Team",
77705
+ homepage: "https://github.com/NousResearch/hermes-agent",
77706
+ runtime: hermesRuntimeMetadata
77707
+ },
77708
+ state: "installed",
77709
+ hooks: {
77710
+ onLoad: (ctx) => {
77711
+ const settings = resolveCliSettings(ctx.settings);
77712
+ ctx.logger.info(`Hermes Runtime Plugin loaded \u2014 binary=${settings.binaryPath} model=${settings.model ?? "(default)"}`);
77713
+ ctx.emitEvent("hermes-runtime:loaded", {
77714
+ runtimeId: HERMES_RUNTIME_ID,
77715
+ version: HERMES_RUNTIME_VERSION
77716
+ });
77717
+ },
77718
+ onUnload: () => {
77719
+ }
77720
+ },
77721
+ runtime: {
77722
+ metadata: hermesRuntimeMetadata,
77723
+ factory: hermesRuntimeFactory
77724
+ }
77725
+ });
77443
77726
  }
77444
77727
  });
77445
77728
 
77446
- // ../dashboard/src/github.ts
77447
- function delay(ms) {
77448
- return new Promise((resolve17) => setTimeout(resolve17, ms));
77729
+ // ../../plugins/fusion-plugin-openclaw-runtime/dist/pi-module.js
77730
+ import { spawn as spawn5 } from "node:child_process";
77731
+ import { randomUUID as randomUUID11 } from "node:crypto";
77732
+ function asString(v) {
77733
+ return typeof v === "string" && v.trim() !== "" ? v.trim() : void 0;
77449
77734
  }
77450
- function normalizeCheckState(state) {
77451
- switch ((state ?? "").toLowerCase()) {
77452
- case "success":
77453
- return "success";
77454
- case "pending":
77455
- case "queued":
77456
- case "in_progress":
77457
- case "expected":
77458
- return "pending";
77459
- case "failure":
77460
- case "failed":
77461
- case "error":
77462
- return "failure";
77463
- case "cancelled":
77464
- return "cancelled";
77465
- case "timed_out":
77466
- return "timed_out";
77467
- case "action_required":
77468
- return "action_required";
77469
- case "neutral":
77470
- return "neutral";
77471
- case "skipped":
77472
- return "skipped";
77473
- case "stale":
77474
- return "stale";
77475
- case "startup_failure":
77476
- return "startup_failure";
77477
- default:
77478
- return "failure";
77479
- }
77735
+ function asNumber(v) {
77736
+ if (typeof v === "number" && Number.isFinite(v))
77737
+ return v;
77738
+ const s = asString(v);
77739
+ if (s === void 0)
77740
+ return void 0;
77741
+ const n = Number(s);
77742
+ return Number.isFinite(n) ? n : void 0;
77480
77743
  }
77481
- function toPrInfo(input) {
77744
+ function asBool(v) {
77745
+ if (typeof v === "boolean")
77746
+ return v;
77747
+ const s = asString(v);
77748
+ if (s === void 0)
77749
+ return void 0;
77750
+ return s === "1" || s.toLowerCase() === "true";
77751
+ }
77752
+ function stripAnsi(text) {
77753
+ return text.replace(ANSI_RE2, "");
77754
+ }
77755
+ function resolveCliConfig(settings) {
77482
77756
  return {
77483
- url: input.url,
77484
- number: input.number,
77485
- status: input.status,
77486
- title: input.title,
77487
- headBranch: input.headBranch,
77488
- baseBranch: input.baseBranch,
77489
- commentCount: input.commentCount ?? 0,
77490
- lastCommentAt: input.lastCommentAt,
77491
- lastCheckedAt: input.lastCheckedAt
77757
+ binaryPath: asString(settings?.binaryPath) ?? asString(process.env.OPENCLAW_BIN) ?? DEFAULT_BINARY,
77758
+ agentId: asString(settings?.agentId) ?? asString(process.env.OPENCLAW_AGENT_ID) ?? DEFAULT_AGENT_ID,
77759
+ model: asString(settings?.model) ?? asString(process.env.OPENCLAW_MODEL),
77760
+ thinking: asString(settings?.thinking) ?? asString(process.env.OPENCLAW_THINKING) ?? DEFAULT_THINKING,
77761
+ cliTimeoutSec: asNumber(settings?.cliTimeoutSec) ?? asNumber(process.env.OPENCLAW_TIMEOUT_SEC) ?? DEFAULT_TIMEOUT_SEC,
77762
+ cliTimeoutMs: asNumber(settings?.cliTimeoutMs) ?? asNumber(process.env.OPENCLAW_CLI_TIMEOUT_MS) ?? DEFAULT_CLI_TIMEOUT_MS,
77763
+ useGateway: asBool(settings?.useGateway) ?? asBool(process.env.OPENCLAW_USE_GATEWAY) ?? false
77492
77764
  };
77493
77765
  }
77494
- function isPrMergeReady(input) {
77495
- const blockingReasons = [];
77496
- if (input.status !== "open") {
77497
- blockingReasons.push(`PR is ${input.status}`);
77498
- }
77499
- if (input.reviewDecision === "CHANGES_REQUESTED") {
77500
- blockingReasons.push("changes requested review is active");
77501
- }
77502
- const blockingChecks = input.checks.filter(
77503
- (check) => check.required && check.state !== "success"
77504
- );
77505
- if (blockingChecks.length > 0) {
77506
- blockingReasons.push(
77507
- `required checks not successful: ${blockingChecks.map((check) => `${check.name} (${check.state})`).join(", ")}`
77508
- );
77766
+ function buildOpenClawArgs(config, sessionId, message) {
77767
+ const args = ["--no-color", "agent"];
77768
+ if (!config.useGateway)
77769
+ args.push("--local");
77770
+ args.push("--json");
77771
+ args.push("--session-id", sessionId);
77772
+ args.push("--message", message);
77773
+ args.push("--agent", config.agentId);
77774
+ if (config.model) {
77775
+ args.push("--model", config.model);
77509
77776
  }
77777
+ args.push("--thinking", config.thinking);
77778
+ args.push("--timeout", String(config.cliTimeoutSec));
77779
+ return args;
77780
+ }
77781
+ function extractStderrError(stderr, stdout) {
77782
+ const tryExtract = (raw) => {
77783
+ if (!raw)
77784
+ return void 0;
77785
+ const lines = stripAnsi(raw).split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
77786
+ return lines.length > 0 ? lines[lines.length - 1] : void 0;
77787
+ };
77788
+ return tryExtract(stderr) ?? tryExtract(stdout ?? "") ?? "openclaw exited with non-zero status (no stderr)";
77789
+ }
77790
+ function createCliSession(opts) {
77510
77791
  return {
77511
- ready: blockingReasons.length === 0,
77512
- blockingReasons
77792
+ sessionId: randomUUID11(),
77793
+ agentId: opts.agentId ?? DEFAULT_AGENT_ID,
77794
+ systemPrompt: opts.systemPrompt,
77795
+ messages: [{ role: "developer", content: opts.systemPrompt }],
77796
+ lastModelDescription: `openclaw/${opts.agentId ?? DEFAULT_AGENT_ID}`,
77797
+ lastUsage: void 0,
77798
+ callbacks: opts.callbacks
77799
+ };
77800
+ }
77801
+ async function promptCli(session, message, config, callbacks, signal) {
77802
+ const args = buildOpenClawArgs(config, session.sessionId, message);
77803
+ const cb = { ...session.callbacks, ...callbacks };
77804
+ cb.onToolStart?.("openclaw.agent", { sessionId: session.sessionId });
77805
+ return new Promise((resolve17, reject) => {
77806
+ let settled = false;
77807
+ const child = spawn5(config.binaryPath, args, {
77808
+ stdio: ["ignore", "pipe", "pipe"]
77809
+ });
77810
+ const hardKill = setTimeout(() => {
77811
+ if (settled)
77812
+ return;
77813
+ settled = true;
77814
+ try {
77815
+ child.kill("SIGKILL");
77816
+ } catch {
77817
+ }
77818
+ reject(new Error(`openclaw: process timed out after ${config.cliTimeoutMs}ms`));
77819
+ }, config.cliTimeoutMs);
77820
+ const onAbort = () => {
77821
+ if (settled)
77822
+ return;
77823
+ try {
77824
+ child.kill("SIGTERM");
77825
+ } catch {
77826
+ }
77827
+ };
77828
+ if (signal) {
77829
+ if (signal.aborted) {
77830
+ onAbort();
77831
+ } else {
77832
+ signal.addEventListener("abort", onAbort, { once: true });
77833
+ }
77834
+ }
77835
+ let stdout = "";
77836
+ let stderr = "";
77837
+ child.stdout?.on("data", (chunk) => {
77838
+ stdout += chunk.toString("utf-8");
77839
+ });
77840
+ child.stderr?.on("data", (chunk) => {
77841
+ stderr += chunk.toString("utf-8");
77842
+ });
77843
+ child.on("error", (err) => {
77844
+ if (settled)
77845
+ return;
77846
+ settled = true;
77847
+ clearTimeout(hardKill);
77848
+ signal?.removeEventListener("abort", onAbort);
77849
+ const isNotFound = err.code === "ENOENT";
77850
+ reject(new Error(isNotFound ? `openclaw: binary not found at "${config.binaryPath}". Install OpenClaw (npm i -g openclaw) or set binaryPath/OPENCLAW_BIN.` : `openclaw: spawn error \u2014 ${err.message}`));
77851
+ });
77852
+ child.on("close", (code) => {
77853
+ if (settled)
77854
+ return;
77855
+ settled = true;
77856
+ clearTimeout(hardKill);
77857
+ signal?.removeEventListener("abort", onAbort);
77858
+ if (code !== 0) {
77859
+ const err = stderr.trim() || stdout.trim() ? extractStderrError(stderr, stdout) : `openclaw: exited with code ${String(code)}`;
77860
+ reject(new Error(err));
77861
+ return;
77862
+ }
77863
+ let parsed;
77864
+ try {
77865
+ parsed = JSON.parse(stdout);
77866
+ } catch {
77867
+ reject(new Error(`openclaw: failed to parse JSON output (stdout=${stdout.slice(0, 200)})`));
77868
+ return;
77869
+ }
77870
+ const payloads = parsed.payloads ?? [];
77871
+ const visibleText = payloads.filter((p) => !p.isError && !p.isReasoning).map((p) => p.text ?? "").filter((t) => t.length > 0).join("");
77872
+ const reasoningText = payloads.filter((p) => p.isReasoning).map((p) => p.text ?? "").filter((t) => t.length > 0).join("\n");
77873
+ const errorText = payloads.filter((p) => p.isError).map((p) => p.text ?? "").filter((t) => t.length > 0);
77874
+ const finalText = visibleText || parsed.meta?.finalAssistantVisibleText || "";
77875
+ if (finalText)
77876
+ cb.onText?.(finalText);
77877
+ if (reasoningText)
77878
+ cb.onThinking?.(reasoningText);
77879
+ session.messages.push({ role: "user", content: message });
77880
+ if (finalText) {
77881
+ session.messages.push({ role: "assistant", content: finalText });
77882
+ }
77883
+ const agentMeta = parsed.meta?.agentMeta;
77884
+ if (agentMeta?.usage)
77885
+ session.lastUsage = agentMeta.usage;
77886
+ if (agentMeta?.provider && agentMeta.model) {
77887
+ session.lastModelDescription = `openclaw/${session.agentId}/${agentMeta.provider}/${agentMeta.model}`;
77888
+ }
77889
+ const metaError = parsed.meta?.error;
77890
+ const isError = !!metaError;
77891
+ cb.onToolEnd?.("openclaw.agent", isError, {
77892
+ usage: agentMeta?.usage,
77893
+ provider: agentMeta?.provider,
77894
+ model: agentMeta?.model,
77895
+ ...metaError ? { error: metaError } : {},
77896
+ ...errorText.length > 0 ? { toolErrors: errorText } : {}
77897
+ });
77898
+ resolve17();
77899
+ });
77900
+ });
77901
+ }
77902
+ function describeCliModel(session) {
77903
+ return session.lastModelDescription || `openclaw/${session.agentId}`;
77904
+ }
77905
+ var DEFAULT_BINARY, DEFAULT_AGENT_ID, DEFAULT_THINKING, DEFAULT_TIMEOUT_SEC, DEFAULT_CLI_TIMEOUT_MS, ANSI_RE2;
77906
+ var init_pi_module = __esm({
77907
+ "../../plugins/fusion-plugin-openclaw-runtime/dist/pi-module.js"() {
77908
+ "use strict";
77909
+ DEFAULT_BINARY = "openclaw";
77910
+ DEFAULT_AGENT_ID = "main";
77911
+ DEFAULT_THINKING = "off";
77912
+ DEFAULT_TIMEOUT_SEC = 0;
77913
+ DEFAULT_CLI_TIMEOUT_MS = 3e5;
77914
+ ANSI_RE2 = /\x1b\[[0-9;]*[A-Za-z]/g;
77915
+ }
77916
+ });
77917
+
77918
+ // ../../plugins/fusion-plugin-openclaw-runtime/dist/runtime-adapter.js
77919
+ var OpenClawRuntimeAdapter;
77920
+ var init_runtime_adapter2 = __esm({
77921
+ "../../plugins/fusion-plugin-openclaw-runtime/dist/runtime-adapter.js"() {
77922
+ "use strict";
77923
+ init_pi_module();
77924
+ OpenClawRuntimeAdapter = class {
77925
+ id = "openclaw";
77926
+ name = "OpenClaw Runtime";
77927
+ config;
77928
+ constructor(settings) {
77929
+ this.config = resolveCliConfig(settings);
77930
+ }
77931
+ async createSession(options) {
77932
+ const session = createCliSession({
77933
+ systemPrompt: options.systemPrompt,
77934
+ agentId: this.config.agentId,
77935
+ callbacks: {
77936
+ onText: options.onText,
77937
+ onThinking: options.onThinking,
77938
+ onToolStart: options.onToolStart,
77939
+ onToolEnd: options.onToolEnd
77940
+ }
77941
+ });
77942
+ return { session, sessionFile: void 0 };
77943
+ }
77944
+ async promptWithFallback(session, prompt, options) {
77945
+ const overrideCallbacks = options ?? void 0;
77946
+ await promptCli(session, prompt, this.config, overrideCallbacks);
77947
+ }
77948
+ describeModel(session) {
77949
+ return describeCliModel(session);
77950
+ }
77951
+ async dispose(_session) {
77952
+ }
77953
+ };
77954
+ }
77955
+ });
77956
+
77957
+ // ../../plugins/fusion-plugin-openclaw-runtime/dist/probe.js
77958
+ import { spawn as spawn6 } from "node:child_process";
77959
+ async function probeOpenClawBinary(opts = {}) {
77960
+ const startedAt = Date.now();
77961
+ const binary = opts.binaryPath ?? "openclaw";
77962
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
77963
+ const resolvedPath = await tryResolveBinaryPath(binary);
77964
+ return new Promise((resolvePromise) => {
77965
+ const finish = (partial) => {
77966
+ resolvePromise({ ...partial, probeDurationMs: Date.now() - startedAt });
77967
+ };
77968
+ let settled = false;
77969
+ const child = spawn6(resolvedPath ?? binary, ["--version"], {
77970
+ stdio: ["ignore", "pipe", "pipe"]
77971
+ });
77972
+ const timer = setTimeout(() => {
77973
+ if (settled)
77974
+ return;
77975
+ settled = true;
77976
+ try {
77977
+ child.kill("SIGKILL");
77978
+ } catch {
77979
+ }
77980
+ finish({
77981
+ available: false,
77982
+ binaryPath: resolvedPath,
77983
+ reason: `Probe timed out after ${timeoutMs}ms`
77984
+ });
77985
+ }, timeoutMs);
77986
+ let stdout = "";
77987
+ let stderr = "";
77988
+ child.stdout?.on("data", (chunk) => {
77989
+ stdout += chunk.toString("utf-8");
77990
+ });
77991
+ child.stderr?.on("data", (chunk) => {
77992
+ stderr += chunk.toString("utf-8");
77993
+ });
77994
+ child.on("error", (err) => {
77995
+ if (settled)
77996
+ return;
77997
+ settled = true;
77998
+ clearTimeout(timer);
77999
+ const isNotFound = err.code === "ENOENT";
78000
+ finish({
78001
+ available: false,
78002
+ binaryPath: resolvedPath,
78003
+ reason: isNotFound ? `\`${binary}\` not found on PATH \u2014 install via: npm install -g openclaw` : err.message
78004
+ });
78005
+ });
78006
+ child.on("close", (code) => {
78007
+ if (settled)
78008
+ return;
78009
+ settled = true;
78010
+ clearTimeout(timer);
78011
+ if (code === 0) {
78012
+ finish({
78013
+ available: true,
78014
+ binaryPath: resolvedPath,
78015
+ version: stdout.trim() || void 0
78016
+ });
78017
+ } else {
78018
+ finish({
78019
+ available: false,
78020
+ binaryPath: resolvedPath,
78021
+ reason: stderr.trim() || `openclaw --version exited with code ${String(code)}`
78022
+ });
78023
+ }
78024
+ });
78025
+ });
78026
+ }
78027
+ async function tryResolveBinaryPath(binary) {
78028
+ return new Promise((resolvePromise) => {
78029
+ const which = process.platform === "win32" ? "where" : "which";
78030
+ const child = spawn6(which, [binary], { stdio: ["ignore", "pipe", "ignore"] });
78031
+ let out = "";
78032
+ child.stdout?.on("data", (chunk) => {
78033
+ out += chunk.toString("utf-8");
78034
+ });
78035
+ child.on("error", () => resolvePromise(void 0));
78036
+ child.on("close", (code) => {
78037
+ if (code === 0) {
78038
+ const first = out.trim().split(/\r?\n/)[0];
78039
+ resolvePromise(first?.length ? first : void 0);
78040
+ } else {
78041
+ resolvePromise(void 0);
78042
+ }
78043
+ });
78044
+ });
78045
+ }
78046
+ var DEFAULT_PROBE_TIMEOUT_MS;
78047
+ var init_probe2 = __esm({
78048
+ "../../plugins/fusion-plugin-openclaw-runtime/dist/probe.js"() {
78049
+ "use strict";
78050
+ DEFAULT_PROBE_TIMEOUT_MS = 2e3;
78051
+ }
78052
+ });
78053
+
78054
+ // ../../plugins/fusion-plugin-openclaw-runtime/dist/index.js
78055
+ var OPENCLAW_RUNTIME_ID, OPENCLAW_RUNTIME_VERSION, openclawRuntimeMetadata, openclawRuntimeFactory, plugin2;
78056
+ var init_dist2 = __esm({
78057
+ "../../plugins/fusion-plugin-openclaw-runtime/dist/index.js"() {
78058
+ "use strict";
78059
+ init_src3();
78060
+ init_runtime_adapter2();
78061
+ init_pi_module();
78062
+ init_probe2();
78063
+ init_runtime_adapter2();
78064
+ init_pi_module();
78065
+ init_probe2();
78066
+ OPENCLAW_RUNTIME_ID = "openclaw";
78067
+ OPENCLAW_RUNTIME_VERSION = "0.2.0";
78068
+ openclawRuntimeMetadata = {
78069
+ runtimeId: OPENCLAW_RUNTIME_ID,
78070
+ name: "OpenClaw Runtime",
78071
+ description: "Drives the local `openclaw` CLI (openclaw/openclaw)",
78072
+ version: OPENCLAW_RUNTIME_VERSION
78073
+ };
78074
+ openclawRuntimeFactory = async (ctx) => {
78075
+ return new OpenClawRuntimeAdapter(ctx?.settings);
78076
+ };
78077
+ plugin2 = definePlugin({
78078
+ manifest: {
78079
+ id: "fusion-plugin-openclaw-runtime",
78080
+ name: "OpenClaw Runtime Plugin",
78081
+ version: OPENCLAW_RUNTIME_VERSION,
78082
+ description: "Drives the local `openclaw` CLI for Fusion agents \u2014 embedded `--local` mode by default; gateway optional.",
78083
+ author: "Fusion Team",
78084
+ homepage: "https://docs.openclaw.ai/",
78085
+ runtime: openclawRuntimeMetadata
78086
+ },
78087
+ state: "installed",
78088
+ hooks: {
78089
+ onLoad: async (ctx) => {
78090
+ const config = resolveCliConfig(ctx.settings);
78091
+ const probe = await probeOpenClawBinary({ binaryPath: config.binaryPath });
78092
+ ctx.logger.info(probe.available ? `OpenClaw Runtime Plugin loaded \u2014 binary=${config.binaryPath}${probe.version ? ` (${probe.version})` : ""}` : `OpenClaw Runtime Plugin loaded but binary not detected: ${probe.reason ?? "unknown"}`);
78093
+ ctx.emitEvent("openclaw-runtime:loaded", {
78094
+ runtimeId: OPENCLAW_RUNTIME_ID,
78095
+ version: OPENCLAW_RUNTIME_VERSION,
78096
+ binaryAvailable: probe.available,
78097
+ binaryPath: probe.binaryPath ?? config.binaryPath
78098
+ });
78099
+ },
78100
+ onUnload: () => {
78101
+ }
78102
+ },
78103
+ runtime: {
78104
+ metadata: openclawRuntimeMetadata,
78105
+ factory: openclawRuntimeFactory
78106
+ }
78107
+ });
78108
+ }
78109
+ });
78110
+
78111
+ // ../dashboard/src/project-store-resolver.ts
78112
+ var init_project_store_resolver = __esm({
78113
+ "../dashboard/src/project-store-resolver.ts"() {
78114
+ "use strict";
78115
+ }
78116
+ });
78117
+
78118
+ // ../dashboard/src/routes/context.ts
78119
+ import { Router as Router2 } from "express";
78120
+ var init_context = __esm({
78121
+ "../dashboard/src/routes/context.ts"() {
78122
+ "use strict";
78123
+ init_api_error();
78124
+ init_project_store_resolver();
78125
+ init_runtime_logger();
78126
+ }
78127
+ });
78128
+
78129
+ // ../dashboard/src/routes/register-task-workflow-routes.ts
78130
+ var init_register_task_workflow_routes = __esm({
78131
+ "../dashboard/src/routes/register-task-workflow-routes.ts"() {
78132
+ "use strict";
78133
+ init_src();
78134
+ init_api_error();
78135
+ }
78136
+ });
78137
+
78138
+ // ../dashboard/src/routes/register-planning-subtask-routes.ts
78139
+ var init_register_planning_subtask_routes = __esm({
78140
+ "../dashboard/src/routes/register-planning-subtask-routes.ts"() {
78141
+ "use strict";
78142
+ init_api_error();
78143
+ init_sse_buffer();
78144
+ }
78145
+ });
78146
+
78147
+ // ../dashboard/src/rate-limit.ts
78148
+ var init_rate_limit = __esm({
78149
+ "../dashboard/src/rate-limit.ts"() {
78150
+ "use strict";
78151
+ init_api_error();
78152
+ }
78153
+ });
78154
+
78155
+ // ../dashboard/src/routes/register-chat-routes.ts
78156
+ var init_register_chat_routes = __esm({
78157
+ "../dashboard/src/routes/register-chat-routes.ts"() {
78158
+ "use strict";
78159
+ init_api_error();
78160
+ init_rate_limit();
78161
+ init_sse_buffer();
78162
+ }
78163
+ });
78164
+
78165
+ // ../dashboard/src/remote-auth.ts
78166
+ var init_remote_auth = __esm({
78167
+ "../dashboard/src/remote-auth.ts"() {
78168
+ "use strict";
78169
+ }
78170
+ });
78171
+
78172
+ // ../dashboard/src/routes/register-settings-memory-routes.ts
78173
+ var init_register_settings_memory_routes = __esm({
78174
+ "../dashboard/src/routes/register-settings-memory-routes.ts"() {
78175
+ "use strict";
78176
+ init_src();
78177
+ init_api_error();
78178
+ init_remote_auth();
78179
+ init_project_store_resolver();
78180
+ }
78181
+ });
78182
+
78183
+ // ../dashboard/src/terminal-service.ts
78184
+ import { createRequire as createRequire3 } from "node:module";
78185
+ var isBunBinary, require2;
78186
+ var init_terminal_service = __esm({
78187
+ "../dashboard/src/terminal-service.ts"() {
78188
+ "use strict";
78189
+ isBunBinary = typeof Bun !== "undefined" && !!Bun.embeddedFiles;
78190
+ require2 = createRequire3(import.meta.url);
78191
+ }
78192
+ });
78193
+
78194
+ // ../dashboard/src/routes/register-messaging-scripts.ts
78195
+ var init_register_messaging_scripts = __esm({
78196
+ "../dashboard/src/routes/register-messaging-scripts.ts"() {
78197
+ "use strict";
78198
+ init_src();
78199
+ init_api_error();
78200
+ init_terminal_service();
78201
+ }
78202
+ });
78203
+
78204
+ // ../dashboard/src/github.ts
78205
+ function delay(ms) {
78206
+ return new Promise((resolve17) => setTimeout(resolve17, ms));
78207
+ }
78208
+ function normalizeCheckState(state) {
78209
+ switch ((state ?? "").toLowerCase()) {
78210
+ case "success":
78211
+ return "success";
78212
+ case "pending":
78213
+ case "queued":
78214
+ case "in_progress":
78215
+ case "expected":
78216
+ return "pending";
78217
+ case "failure":
78218
+ case "failed":
78219
+ case "error":
78220
+ return "failure";
78221
+ case "cancelled":
78222
+ return "cancelled";
78223
+ case "timed_out":
78224
+ return "timed_out";
78225
+ case "action_required":
78226
+ return "action_required";
78227
+ case "neutral":
78228
+ return "neutral";
78229
+ case "skipped":
78230
+ return "skipped";
78231
+ case "stale":
78232
+ return "stale";
78233
+ case "startup_failure":
78234
+ return "startup_failure";
78235
+ default:
78236
+ return "failure";
78237
+ }
78238
+ }
78239
+ function toPrInfo(input) {
78240
+ return {
78241
+ url: input.url,
78242
+ number: input.number,
78243
+ status: input.status,
78244
+ title: input.title,
78245
+ headBranch: input.headBranch,
78246
+ baseBranch: input.baseBranch,
78247
+ commentCount: input.commentCount ?? 0,
78248
+ lastCommentAt: input.lastCommentAt,
78249
+ lastCheckedAt: input.lastCheckedAt
78250
+ };
78251
+ }
78252
+ function isPrMergeReady(input) {
78253
+ const blockingReasons = [];
78254
+ if (input.status !== "open") {
78255
+ blockingReasons.push(`PR is ${input.status}`);
78256
+ }
78257
+ if (input.reviewDecision === "CHANGES_REQUESTED") {
78258
+ blockingReasons.push("changes requested review is active");
78259
+ }
78260
+ const blockingChecks = input.checks.filter(
78261
+ (check) => check.required && check.state !== "success"
78262
+ );
78263
+ if (blockingChecks.length > 0) {
78264
+ blockingReasons.push(
78265
+ `required checks not successful: ${blockingChecks.map((check) => `${check.name} (${check.state})`).join(", ")}`
78266
+ );
78267
+ }
78268
+ return {
78269
+ ready: blockingReasons.length === 0,
78270
+ blockingReasons
77513
78271
  };
77514
78272
  }
77515
78273
  function uniqueBatchNumbers(numbers) {
@@ -78329,10 +79087,10 @@ var init_github = __esm({
78329
79087
  return issues;
78330
79088
  }
78331
79089
  async listRecentIssueStatusPage(owner, repo) {
78332
- const path = `repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues?state=all&per_page=${MAX_BADGE_BATCH_SIZE}`;
79090
+ const path2 = `repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues?state=all&per_page=${MAX_BADGE_BATCH_SIZE}`;
78333
79091
  if (this.hasGhAuth()) {
78334
79092
  try {
78335
- return await runGhJsonAsync(["api", path]);
79093
+ return await runGhJsonAsync(["api", path2]);
78336
79094
  } catch (err) {
78337
79095
  if (this.token) {
78338
79096
  return this.listRecentIssueStatusPageWithApi(owner, repo);
@@ -78374,10 +79132,10 @@ var init_github = __esm({
78374
79132
  return prs;
78375
79133
  }
78376
79134
  async listRecentPrStatusPage(owner, repo) {
78377
- const path = `repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls?state=all&per_page=${MAX_BADGE_BATCH_SIZE}`;
79135
+ const path2 = `repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls?state=all&per_page=${MAX_BADGE_BATCH_SIZE}`;
78378
79136
  if (this.hasGhAuth()) {
78379
79137
  try {
78380
- return await runGhJsonAsync(["api", path]);
79138
+ return await runGhJsonAsync(["api", path2]);
78381
79139
  } catch (err) {
78382
79140
  if (this.token) {
78383
79141
  return this.listRecentPrStatusPageWithApi(owner, repo);
@@ -79284,8 +80042,8 @@ var init_register_git_github = __esm({
79284
80042
  });
79285
80043
 
79286
80044
  // ../dashboard/src/terminal.ts
79287
- import { spawn as spawn4 } from "node:child_process";
79288
- import { randomUUID as randomUUID11 } from "node:crypto";
80045
+ import { spawn as spawn7 } from "node:child_process";
80046
+ import { randomUUID as randomUUID12 } from "node:crypto";
79289
80047
  import { EventEmitter as EventEmitter28 } from "node:events";
79290
80048
  function extractBaseCommand(command) {
79291
80049
  let trimmed = command.trim();
@@ -79445,8 +80203,8 @@ var init_terminal = __esm({
79445
80203
  if (!validation.valid) {
79446
80204
  return { sessionId: "", error: validation.error };
79447
80205
  }
79448
- const sessionId = randomUUID11();
79449
- const childProcess = spawn4(command, [], {
80206
+ const sessionId = randomUUID12();
80207
+ const childProcess = spawn7(command, [], {
79450
80208
  cwd,
79451
80209
  shell: true,
79452
80210
  stdio: ["pipe", "pipe", "pipe"],
@@ -79871,728 +80629,13 @@ var init_register_auth_routes = __esm({
79871
80629
  }
79872
80630
  });
79873
80631
 
79874
- // ../plugin-sdk/src/index.ts
79875
- function definePlugin(plugin4) {
79876
- return plugin4;
79877
- }
79878
- var init_src3 = __esm({
79879
- "../plugin-sdk/src/index.ts"() {
79880
- "use strict";
79881
- init_src();
79882
- }
79883
- });
79884
-
79885
- // ../../plugins/fusion-plugin-hermes-runtime/dist/cli-spawn.js
79886
- import { spawn as spawn5, spawnSync } from "node:child_process";
79887
- import { sep as PATH_SEP } from "node:path";
79888
- function resolveBinaryForSpawn(binary) {
79889
- if (process.platform !== "win32")
79890
- return binary;
79891
- if (binary.includes(PATH_SEP) || binary.includes("/") || /\.[a-z]{2,4}$/i.test(binary)) {
79892
- return binary;
79893
- }
79894
- const cached = resolvedBinaryCache.get(binary);
79895
- if (cached)
79896
- return cached;
79897
- try {
79898
- const result = spawnSync("where", [binary], { encoding: "utf-8" });
79899
- if (result.status === 0) {
79900
- const first = (result.stdout ?? "").trim().split(/\r?\n/)[0];
79901
- if (first?.length) {
79902
- resolvedBinaryCache.set(binary, first);
79903
- return first;
79904
- }
79905
- }
79906
- } catch {
79907
- }
79908
- return binary;
79909
- }
79910
- function hermesProfileHome(profileName) {
79911
- const base = process.env.HERMES_HOME ?? `${process.env.HOME ?? "~"}/.hermes`;
79912
- if (profileName === "default" || profileName === "")
79913
- return base;
79914
- return `${base}/profiles/${profileName}`;
79915
- }
79916
- function resolveCliSettings(settings) {
79917
- const str = (v) => typeof v === "string" && v.trim().length > 0 ? v.trim() : void 0;
79918
- const num = (v, envKey, fallback) => {
79919
- if (typeof v === "number" && Number.isFinite(v) && v > 0)
79920
- return v;
79921
- const raw = str(v) ?? str(process.env[envKey]);
79922
- if (raw !== void 0) {
79923
- const parsed = Number(raw);
79924
- if (Number.isFinite(parsed) && parsed > 0)
79925
- return parsed;
79926
- }
79927
- return fallback;
79928
- };
79929
- const bool = (v, envKey, fallback) => {
79930
- if (typeof v === "boolean")
79931
- return v;
79932
- const raw = str(v) ?? str(process.env[envKey]);
79933
- if (raw !== void 0)
79934
- return raw === "1" || raw.toLowerCase() === "true";
79935
- return fallback;
79936
- };
79937
- return {
79938
- binaryPath: str(settings?.binaryPath) ?? str(process.env.HERMES_BIN) ?? "hermes",
79939
- model: str(settings?.model) ?? str(process.env.HERMES_MODEL_ID),
79940
- provider: str(settings?.provider) ?? str(process.env.HERMES_PROVIDER),
79941
- maxTurns: num(settings?.maxTurns, "HERMES_MAX_TURNS", 12),
79942
- yolo: bool(settings?.yolo, "HERMES_YOLO", false),
79943
- cliTimeoutMs: num(settings?.cliTimeoutMs, "HERMES_CLI_TIMEOUT_MS", 3e5),
79944
- profile: str(settings?.profile) ?? str(process.env.HERMES_PROFILE)
79945
- };
79946
- }
79947
- function cleanText(raw) {
79948
- return raw.replace(ANSI_RE, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
79949
- }
79950
- function stripChrome(text) {
79951
- const lines = text.split("\n");
79952
- const filtered = lines.filter((line) => !CHROME_LINE_RES.some((re) => re.test(line)));
79953
- return filtered.join("\n").trim();
79954
- }
79955
- function parseHermesOutput(rawStdout, rawStderr) {
79956
- const cleaned = cleanText(rawStdout);
79957
- const match = SESSION_ID_RE.exec(cleaned);
79958
- if (!match) {
79959
- const combined = [rawStdout, rawStderr].filter(Boolean).join("\n");
79960
- throw new Error(`hermes: missing session_id in output.
79961
- ${combined}`);
79962
- }
79963
- const sessionId = match[1];
79964
- const sessionIdLineStart = cleaned.lastIndexOf("\nsession_id:");
79965
- const bodyRaw = sessionIdLineStart >= 0 ? cleaned.slice(0, sessionIdLineStart) : cleaned;
79966
- const body = stripChrome(bodyRaw);
79967
- return { body, sessionId };
79968
- }
79969
- function buildHermesArgs(prompt, settings, resumeSessionId) {
79970
- const args = ["chat", "-q", prompt, "-Q", "--source", "tool"];
79971
- if (resumeSessionId) {
79972
- args.push("--resume", resumeSessionId);
79973
- }
79974
- if (settings.model) {
79975
- args.push("-m", settings.model);
79976
- }
79977
- if (settings.provider) {
79978
- args.push("--provider", settings.provider);
79979
- }
79980
- args.push("--max-turns", String(settings.maxTurns));
79981
- if (settings.yolo) {
79982
- args.push("--yolo");
79983
- }
79984
- return args;
79985
- }
79986
- async function invokeHermesCli(prompt, settings, resumeSessionId, signal) {
79987
- const args = buildHermesArgs(prompt, settings, resumeSessionId);
79988
- const binary = resolveBinaryForSpawn(settings.binaryPath);
79989
- return new Promise((resolve17, reject) => {
79990
- let settled = false;
79991
- const spawnEnv = { ...process.env, PYTHONUNBUFFERED: "1" };
79992
- if (settings.profile) {
79993
- spawnEnv.HERMES_HOME = hermesProfileHome(settings.profile);
79994
- }
79995
- const child = spawn5(binary, args, {
79996
- stdio: ["ignore", "pipe", "pipe"],
79997
- env: spawnEnv
79998
- });
79999
- const hardKillTimer = setTimeout(() => {
80000
- if (settled)
80001
- return;
80002
- settled = true;
80003
- try {
80004
- child.kill("SIGKILL");
80005
- } catch {
80006
- }
80007
- reject(new Error(`hermes: process timed out after ${settings.cliTimeoutMs}ms`));
80008
- }, settings.cliTimeoutMs);
80009
- const onAbort = () => {
80010
- if (settled)
80011
- return;
80012
- settled = true;
80013
- clearTimeout(hardKillTimer);
80014
- try {
80015
- child.kill("SIGTERM");
80016
- } catch {
80017
- }
80018
- reject(new Error("hermes: invocation aborted"));
80019
- };
80020
- if (signal) {
80021
- if (signal.aborted) {
80022
- onAbort();
80023
- return;
80024
- }
80025
- signal.addEventListener("abort", onAbort, { once: true });
80026
- }
80027
- let stdout = "";
80028
- let stderr = "";
80029
- child.stdout?.on("data", (chunk) => {
80030
- stdout += chunk.toString("utf-8");
80031
- });
80032
- child.stderr?.on("data", (chunk) => {
80033
- stderr += chunk.toString("utf-8");
80034
- });
80035
- child.on("error", (err) => {
80036
- if (settled)
80037
- return;
80038
- settled = true;
80039
- clearTimeout(hardKillTimer);
80040
- signal?.removeEventListener("abort", onAbort);
80041
- const isNotFound = err.code === "ENOENT";
80042
- reject(new Error(isNotFound ? `hermes: binary not found at "${settings.binaryPath}". Install hermes or set binaryPath/HERMES_BIN.` : `hermes: spawn error \u2014 ${err.message}`));
80043
- });
80044
- child.on("close", (code) => {
80045
- if (settled)
80046
- return;
80047
- settled = true;
80048
- clearTimeout(hardKillTimer);
80049
- signal?.removeEventListener("abort", onAbort);
80050
- if (code !== 0) {
80051
- const combined = [stdout, stderr].filter(Boolean).join("\n");
80052
- reject(new Error(`hermes: process exited with code ${String(code)}.
80053
- ${combined}`));
80054
- return;
80055
- }
80056
- try {
80057
- resolve17(parseHermesOutput(stdout, stderr));
80058
- } catch (parseErr) {
80059
- reject(parseErr);
80060
- }
80061
- });
80062
- });
80063
- }
80064
- var resolvedBinaryCache, ANSI_RE, SESSION_ID_RE, CHROME_LINE_RES;
80065
- var init_cli_spawn = __esm({
80066
- "../../plugins/fusion-plugin-hermes-runtime/dist/cli-spawn.js"() {
80067
- "use strict";
80068
- resolvedBinaryCache = /* @__PURE__ */ new Map();
80069
- ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]/g;
80070
- SESSION_ID_RE = /^session_id:\s+([0-9]{8}_[0-9]{6}_[0-9a-f]{6})\s*$/m;
80071
- CHROME_LINE_RES = [
80072
- /^\s*┊\s/,
80073
- // memory/status sidebar lines
80074
- /^↻ Resumed session /,
80075
- // resume banner
80076
- /^╭─.*╮\s*$/,
80077
- // top box border
80078
- /^╰─.*╯\s*$/,
80079
- // bottom box border
80080
- /^Query:\s*/
80081
- // query echo line
80082
- ];
80083
- }
80084
- });
80085
-
80086
- // ../../plugins/fusion-plugin-hermes-runtime/dist/runtime-adapter.js
80087
- var HermesRuntimeAdapter;
80088
- var init_runtime_adapter = __esm({
80089
- "../../plugins/fusion-plugin-hermes-runtime/dist/runtime-adapter.js"() {
80090
- "use strict";
80091
- init_cli_spawn();
80092
- HermesRuntimeAdapter = class {
80093
- id = "hermes";
80094
- name = "Hermes Runtime";
80095
- settings;
80096
- constructor(settings) {
80097
- this.settings = resolveCliSettings(settings);
80098
- }
80099
- async createSession(options) {
80100
- const session = {
80101
- model: void 0,
80102
- systemPrompt: options.systemPrompt,
80103
- messages: [],
80104
- apiKey: void 0,
80105
- thinkingLevel: void 0,
80106
- sessionId: "",
80107
- lastModelDescription: this.describeFromSettings(),
80108
- callbacks: {
80109
- onText: options.onText,
80110
- onThinking: options.onThinking,
80111
- onToolStart: options.onToolStart,
80112
- onToolEnd: options.onToolEnd
80113
- },
80114
- dispose: () => void 0
80115
- };
80116
- return { session, sessionFile: void 0 };
80117
- }
80118
- async promptWithFallback(session, prompt, _options) {
80119
- const resumeId = session.sessionId || void 0;
80120
- const result = await invokeHermesCli(prompt, this.settings, resumeId);
80121
- session.sessionId = result.sessionId;
80122
- session.lastModelDescription = this.describeFromSettings();
80123
- if (result.body) {
80124
- session.callbacks.onText?.(result.body);
80125
- }
80126
- }
80127
- describeModel(session) {
80128
- return session.lastModelDescription || this.describeFromSettings();
80129
- }
80130
- async dispose(_session) {
80131
- }
80132
- describeFromSettings() {
80133
- const provider = this.settings.provider;
80134
- const model = this.settings.model;
80135
- if (provider && model)
80136
- return `hermes/${provider}/${model}`;
80137
- if (model)
80138
- return `hermes/${model}`;
80139
- if (provider)
80140
- return `hermes/${provider}`;
80141
- return "hermes";
80142
- }
80143
- };
80144
- }
80145
- });
80146
-
80147
- // ../../plugins/fusion-plugin-hermes-runtime/dist/probe.js
80148
- var init_probe = __esm({
80149
- "../../plugins/fusion-plugin-hermes-runtime/dist/probe.js"() {
80150
- "use strict";
80151
- }
80152
- });
80153
-
80154
- // ../../plugins/fusion-plugin-hermes-runtime/dist/index.js
80155
- var HERMES_RUNTIME_ID, HERMES_RUNTIME_VERSION, hermesRuntimeMetadata, hermesRuntimeFactory, plugin;
80156
- var init_dist = __esm({
80157
- "../../plugins/fusion-plugin-hermes-runtime/dist/index.js"() {
80158
- "use strict";
80159
- init_src3();
80160
- init_cli_spawn();
80161
- init_runtime_adapter();
80162
- init_runtime_adapter();
80163
- init_cli_spawn();
80164
- init_probe();
80165
- HERMES_RUNTIME_ID = "hermes";
80166
- HERMES_RUNTIME_VERSION = "0.2.0";
80167
- hermesRuntimeMetadata = {
80168
- runtimeId: HERMES_RUNTIME_ID,
80169
- name: "Hermes Runtime",
80170
- description: "Drives the local `hermes` CLI (NousResearch/hermes-agent)",
80171
- version: HERMES_RUNTIME_VERSION
80172
- };
80173
- hermesRuntimeFactory = async (ctx) => {
80174
- return new HermesRuntimeAdapter(ctx.settings);
80175
- };
80176
- plugin = definePlugin({
80177
- manifest: {
80178
- id: "fusion-plugin-hermes-runtime",
80179
- name: "Hermes Runtime Plugin",
80180
- version: HERMES_RUNTIME_VERSION,
80181
- description: "Drives the local `hermes` CLI for Fusion agents \u2014 captures session ids and resumes via --resume.",
80182
- author: "Fusion Team",
80183
- homepage: "https://github.com/NousResearch/hermes-agent",
80184
- runtime: hermesRuntimeMetadata
80185
- },
80186
- state: "installed",
80187
- hooks: {
80188
- onLoad: (ctx) => {
80189
- const settings = resolveCliSettings(ctx.settings);
80190
- ctx.logger.info(`Hermes Runtime Plugin loaded \u2014 binary=${settings.binaryPath} model=${settings.model ?? "(default)"}`);
80191
- ctx.emitEvent("hermes-runtime:loaded", {
80192
- runtimeId: HERMES_RUNTIME_ID,
80193
- version: HERMES_RUNTIME_VERSION
80194
- });
80195
- },
80196
- onUnload: () => {
80197
- }
80198
- },
80199
- runtime: {
80200
- metadata: hermesRuntimeMetadata,
80201
- factory: hermesRuntimeFactory
80202
- }
80203
- });
80204
- }
80205
- });
80206
-
80207
- // ../../plugins/fusion-plugin-openclaw-runtime/dist/pi-module.js
80208
- import { spawn as spawn6 } from "node:child_process";
80209
- import { randomUUID as randomUUID12 } from "node:crypto";
80210
- function asString(v) {
80211
- return typeof v === "string" && v.trim() !== "" ? v.trim() : void 0;
80212
- }
80213
- function asNumber(v) {
80214
- if (typeof v === "number" && Number.isFinite(v))
80215
- return v;
80216
- const s = asString(v);
80217
- if (s === void 0)
80218
- return void 0;
80219
- const n = Number(s);
80220
- return Number.isFinite(n) ? n : void 0;
80221
- }
80222
- function asBool(v) {
80223
- if (typeof v === "boolean")
80224
- return v;
80225
- const s = asString(v);
80226
- if (s === void 0)
80227
- return void 0;
80228
- return s === "1" || s.toLowerCase() === "true";
80229
- }
80230
- function stripAnsi(text) {
80231
- return text.replace(ANSI_RE2, "");
80232
- }
80233
- function resolveCliConfig(settings) {
80234
- return {
80235
- binaryPath: asString(settings?.binaryPath) ?? asString(process.env.OPENCLAW_BIN) ?? DEFAULT_BINARY,
80236
- agentId: asString(settings?.agentId) ?? asString(process.env.OPENCLAW_AGENT_ID) ?? DEFAULT_AGENT_ID,
80237
- model: asString(settings?.model) ?? asString(process.env.OPENCLAW_MODEL),
80238
- thinking: asString(settings?.thinking) ?? asString(process.env.OPENCLAW_THINKING) ?? DEFAULT_THINKING,
80239
- cliTimeoutSec: asNumber(settings?.cliTimeoutSec) ?? asNumber(process.env.OPENCLAW_TIMEOUT_SEC) ?? DEFAULT_TIMEOUT_SEC,
80240
- cliTimeoutMs: asNumber(settings?.cliTimeoutMs) ?? asNumber(process.env.OPENCLAW_CLI_TIMEOUT_MS) ?? DEFAULT_CLI_TIMEOUT_MS,
80241
- useGateway: asBool(settings?.useGateway) ?? asBool(process.env.OPENCLAW_USE_GATEWAY) ?? false
80242
- };
80243
- }
80244
- function buildOpenClawArgs(config, sessionId, message) {
80245
- const args = ["--no-color", "agent"];
80246
- if (!config.useGateway)
80247
- args.push("--local");
80248
- args.push("--json");
80249
- args.push("--session-id", sessionId);
80250
- args.push("--message", message);
80251
- args.push("--agent", config.agentId);
80252
- if (config.model) {
80253
- args.push("--model", config.model);
80254
- }
80255
- args.push("--thinking", config.thinking);
80256
- args.push("--timeout", String(config.cliTimeoutSec));
80257
- return args;
80258
- }
80259
- function extractStderrError(stderr, stdout) {
80260
- const tryExtract = (raw) => {
80261
- if (!raw)
80262
- return void 0;
80263
- const lines = stripAnsi(raw).split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
80264
- return lines.length > 0 ? lines[lines.length - 1] : void 0;
80265
- };
80266
- return tryExtract(stderr) ?? tryExtract(stdout ?? "") ?? "openclaw exited with non-zero status (no stderr)";
80267
- }
80268
- function createCliSession(opts) {
80269
- return {
80270
- sessionId: randomUUID12(),
80271
- agentId: opts.agentId ?? DEFAULT_AGENT_ID,
80272
- systemPrompt: opts.systemPrompt,
80273
- messages: [{ role: "developer", content: opts.systemPrompt }],
80274
- lastModelDescription: `openclaw/${opts.agentId ?? DEFAULT_AGENT_ID}`,
80275
- lastUsage: void 0,
80276
- callbacks: opts.callbacks
80277
- };
80278
- }
80279
- async function promptCli(session, message, config, callbacks, signal) {
80280
- const args = buildOpenClawArgs(config, session.sessionId, message);
80281
- const cb = { ...session.callbacks, ...callbacks };
80282
- cb.onToolStart?.("openclaw.agent", { sessionId: session.sessionId });
80283
- return new Promise((resolve17, reject) => {
80284
- let settled = false;
80285
- const child = spawn6(config.binaryPath, args, {
80286
- stdio: ["ignore", "pipe", "pipe"]
80287
- });
80288
- const hardKill = setTimeout(() => {
80289
- if (settled)
80290
- return;
80291
- settled = true;
80292
- try {
80293
- child.kill("SIGKILL");
80294
- } catch {
80295
- }
80296
- reject(new Error(`openclaw: process timed out after ${config.cliTimeoutMs}ms`));
80297
- }, config.cliTimeoutMs);
80298
- const onAbort = () => {
80299
- if (settled)
80300
- return;
80301
- try {
80302
- child.kill("SIGTERM");
80303
- } catch {
80304
- }
80305
- };
80306
- if (signal) {
80307
- if (signal.aborted) {
80308
- onAbort();
80309
- } else {
80310
- signal.addEventListener("abort", onAbort, { once: true });
80311
- }
80312
- }
80313
- let stdout = "";
80314
- let stderr = "";
80315
- child.stdout?.on("data", (chunk) => {
80316
- stdout += chunk.toString("utf-8");
80317
- });
80318
- child.stderr?.on("data", (chunk) => {
80319
- stderr += chunk.toString("utf-8");
80320
- });
80321
- child.on("error", (err) => {
80322
- if (settled)
80323
- return;
80324
- settled = true;
80325
- clearTimeout(hardKill);
80326
- signal?.removeEventListener("abort", onAbort);
80327
- const isNotFound = err.code === "ENOENT";
80328
- reject(new Error(isNotFound ? `openclaw: binary not found at "${config.binaryPath}". Install OpenClaw (npm i -g openclaw) or set binaryPath/OPENCLAW_BIN.` : `openclaw: spawn error \u2014 ${err.message}`));
80329
- });
80330
- child.on("close", (code) => {
80331
- if (settled)
80332
- return;
80333
- settled = true;
80334
- clearTimeout(hardKill);
80335
- signal?.removeEventListener("abort", onAbort);
80336
- if (code !== 0) {
80337
- const err = stderr.trim() || stdout.trim() ? extractStderrError(stderr, stdout) : `openclaw: exited with code ${String(code)}`;
80338
- reject(new Error(err));
80339
- return;
80340
- }
80341
- let parsed;
80342
- try {
80343
- parsed = JSON.parse(stdout);
80344
- } catch {
80345
- reject(new Error(`openclaw: failed to parse JSON output (stdout=${stdout.slice(0, 200)})`));
80346
- return;
80347
- }
80348
- const payloads = parsed.payloads ?? [];
80349
- const visibleText = payloads.filter((p) => !p.isError && !p.isReasoning).map((p) => p.text ?? "").filter((t) => t.length > 0).join("");
80350
- const reasoningText = payloads.filter((p) => p.isReasoning).map((p) => p.text ?? "").filter((t) => t.length > 0).join("\n");
80351
- const errorText = payloads.filter((p) => p.isError).map((p) => p.text ?? "").filter((t) => t.length > 0);
80352
- const finalText = visibleText || parsed.meta?.finalAssistantVisibleText || "";
80353
- if (finalText)
80354
- cb.onText?.(finalText);
80355
- if (reasoningText)
80356
- cb.onThinking?.(reasoningText);
80357
- session.messages.push({ role: "user", content: message });
80358
- if (finalText) {
80359
- session.messages.push({ role: "assistant", content: finalText });
80360
- }
80361
- const agentMeta = parsed.meta?.agentMeta;
80362
- if (agentMeta?.usage)
80363
- session.lastUsage = agentMeta.usage;
80364
- if (agentMeta?.provider && agentMeta.model) {
80365
- session.lastModelDescription = `openclaw/${session.agentId}/${agentMeta.provider}/${agentMeta.model}`;
80366
- }
80367
- const metaError = parsed.meta?.error;
80368
- const isError = !!metaError;
80369
- cb.onToolEnd?.("openclaw.agent", isError, {
80370
- usage: agentMeta?.usage,
80371
- provider: agentMeta?.provider,
80372
- model: agentMeta?.model,
80373
- ...metaError ? { error: metaError } : {},
80374
- ...errorText.length > 0 ? { toolErrors: errorText } : {}
80375
- });
80376
- resolve17();
80377
- });
80378
- });
80379
- }
80380
- function describeCliModel(session) {
80381
- return session.lastModelDescription || `openclaw/${session.agentId}`;
80382
- }
80383
- var DEFAULT_BINARY, DEFAULT_AGENT_ID, DEFAULT_THINKING, DEFAULT_TIMEOUT_SEC, DEFAULT_CLI_TIMEOUT_MS, ANSI_RE2;
80384
- var init_pi_module = __esm({
80385
- "../../plugins/fusion-plugin-openclaw-runtime/dist/pi-module.js"() {
80386
- "use strict";
80387
- DEFAULT_BINARY = "openclaw";
80388
- DEFAULT_AGENT_ID = "main";
80389
- DEFAULT_THINKING = "off";
80390
- DEFAULT_TIMEOUT_SEC = 0;
80391
- DEFAULT_CLI_TIMEOUT_MS = 3e5;
80392
- ANSI_RE2 = /\x1b\[[0-9;]*[A-Za-z]/g;
80393
- }
80394
- });
80395
-
80396
- // ../../plugins/fusion-plugin-openclaw-runtime/dist/runtime-adapter.js
80397
- var OpenClawRuntimeAdapter;
80398
- var init_runtime_adapter2 = __esm({
80399
- "../../plugins/fusion-plugin-openclaw-runtime/dist/runtime-adapter.js"() {
80400
- "use strict";
80401
- init_pi_module();
80402
- OpenClawRuntimeAdapter = class {
80403
- id = "openclaw";
80404
- name = "OpenClaw Runtime";
80405
- config;
80406
- constructor(settings) {
80407
- this.config = resolveCliConfig(settings);
80408
- }
80409
- async createSession(options) {
80410
- const session = createCliSession({
80411
- systemPrompt: options.systemPrompt,
80412
- agentId: this.config.agentId,
80413
- callbacks: {
80414
- onText: options.onText,
80415
- onThinking: options.onThinking,
80416
- onToolStart: options.onToolStart,
80417
- onToolEnd: options.onToolEnd
80418
- }
80419
- });
80420
- return { session, sessionFile: void 0 };
80421
- }
80422
- async promptWithFallback(session, prompt, options) {
80423
- const overrideCallbacks = options ?? void 0;
80424
- await promptCli(session, prompt, this.config, overrideCallbacks);
80425
- }
80426
- describeModel(session) {
80427
- return describeCliModel(session);
80428
- }
80429
- async dispose(_session) {
80430
- }
80431
- };
80432
- }
80433
- });
80434
-
80435
- // ../../plugins/fusion-plugin-openclaw-runtime/dist/probe.js
80436
- import { spawn as spawn7 } from "node:child_process";
80437
- async function probeOpenClawBinary(opts = {}) {
80438
- const startedAt = Date.now();
80439
- const binary = opts.binaryPath ?? "openclaw";
80440
- const timeoutMs = opts.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
80441
- const resolvedPath = await tryResolveBinaryPath(binary);
80442
- return new Promise((resolvePromise) => {
80443
- const finish = (partial) => {
80444
- resolvePromise({ ...partial, probeDurationMs: Date.now() - startedAt });
80445
- };
80446
- let settled = false;
80447
- const child = spawn7(resolvedPath ?? binary, ["--version"], {
80448
- stdio: ["ignore", "pipe", "pipe"]
80449
- });
80450
- const timer = setTimeout(() => {
80451
- if (settled)
80452
- return;
80453
- settled = true;
80454
- try {
80455
- child.kill("SIGKILL");
80456
- } catch {
80457
- }
80458
- finish({
80459
- available: false,
80460
- binaryPath: resolvedPath,
80461
- reason: `Probe timed out after ${timeoutMs}ms`
80462
- });
80463
- }, timeoutMs);
80464
- let stdout = "";
80465
- let stderr = "";
80466
- child.stdout?.on("data", (chunk) => {
80467
- stdout += chunk.toString("utf-8");
80468
- });
80469
- child.stderr?.on("data", (chunk) => {
80470
- stderr += chunk.toString("utf-8");
80471
- });
80472
- child.on("error", (err) => {
80473
- if (settled)
80474
- return;
80475
- settled = true;
80476
- clearTimeout(timer);
80477
- const isNotFound = err.code === "ENOENT";
80478
- finish({
80479
- available: false,
80480
- binaryPath: resolvedPath,
80481
- reason: isNotFound ? `\`${binary}\` not found on PATH \u2014 install via: npm install -g openclaw` : err.message
80482
- });
80483
- });
80484
- child.on("close", (code) => {
80485
- if (settled)
80486
- return;
80487
- settled = true;
80488
- clearTimeout(timer);
80489
- if (code === 0) {
80490
- finish({
80491
- available: true,
80492
- binaryPath: resolvedPath,
80493
- version: stdout.trim() || void 0
80494
- });
80495
- } else {
80496
- finish({
80497
- available: false,
80498
- binaryPath: resolvedPath,
80499
- reason: stderr.trim() || `openclaw --version exited with code ${String(code)}`
80500
- });
80501
- }
80502
- });
80503
- });
80504
- }
80505
- async function tryResolveBinaryPath(binary) {
80506
- return new Promise((resolvePromise) => {
80507
- const which = process.platform === "win32" ? "where" : "which";
80508
- const child = spawn7(which, [binary], { stdio: ["ignore", "pipe", "ignore"] });
80509
- let out = "";
80510
- child.stdout?.on("data", (chunk) => {
80511
- out += chunk.toString("utf-8");
80512
- });
80513
- child.on("error", () => resolvePromise(void 0));
80514
- child.on("close", (code) => {
80515
- if (code === 0) {
80516
- const first = out.trim().split(/\r?\n/)[0];
80517
- resolvePromise(first?.length ? first : void 0);
80518
- } else {
80519
- resolvePromise(void 0);
80520
- }
80521
- });
80522
- });
80523
- }
80524
- var DEFAULT_PROBE_TIMEOUT_MS;
80525
- var init_probe2 = __esm({
80526
- "../../plugins/fusion-plugin-openclaw-runtime/dist/probe.js"() {
80527
- "use strict";
80528
- DEFAULT_PROBE_TIMEOUT_MS = 2e3;
80529
- }
80530
- });
80531
-
80532
- // ../../plugins/fusion-plugin-openclaw-runtime/dist/index.js
80533
- var OPENCLAW_RUNTIME_ID, OPENCLAW_RUNTIME_VERSION, openclawRuntimeMetadata, openclawRuntimeFactory, plugin2;
80534
- var init_dist2 = __esm({
80535
- "../../plugins/fusion-plugin-openclaw-runtime/dist/index.js"() {
80536
- "use strict";
80537
- init_src3();
80538
- init_runtime_adapter2();
80539
- init_pi_module();
80540
- init_probe2();
80541
- init_runtime_adapter2();
80542
- init_pi_module();
80543
- init_probe2();
80544
- OPENCLAW_RUNTIME_ID = "openclaw";
80545
- OPENCLAW_RUNTIME_VERSION = "0.2.0";
80546
- openclawRuntimeMetadata = {
80547
- runtimeId: OPENCLAW_RUNTIME_ID,
80548
- name: "OpenClaw Runtime",
80549
- description: "Drives the local `openclaw` CLI (openclaw/openclaw)",
80550
- version: OPENCLAW_RUNTIME_VERSION
80551
- };
80552
- openclawRuntimeFactory = async (ctx) => {
80553
- return new OpenClawRuntimeAdapter(ctx?.settings);
80554
- };
80555
- plugin2 = definePlugin({
80556
- manifest: {
80557
- id: "fusion-plugin-openclaw-runtime",
80558
- name: "OpenClaw Runtime Plugin",
80559
- version: OPENCLAW_RUNTIME_VERSION,
80560
- description: "Drives the local `openclaw` CLI for Fusion agents \u2014 embedded `--local` mode by default; gateway optional.",
80561
- author: "Fusion Team",
80562
- homepage: "https://docs.openclaw.ai/",
80563
- runtime: openclawRuntimeMetadata
80564
- },
80565
- state: "installed",
80566
- hooks: {
80567
- onLoad: async (ctx) => {
80568
- const config = resolveCliConfig(ctx.settings);
80569
- const probe = await probeOpenClawBinary({ binaryPath: config.binaryPath });
80570
- ctx.logger.info(probe.available ? `OpenClaw Runtime Plugin loaded \u2014 binary=${config.binaryPath}${probe.version ? ` (${probe.version})` : ""}` : `OpenClaw Runtime Plugin loaded but binary not detected: ${probe.reason ?? "unknown"}`);
80571
- ctx.emitEvent("openclaw-runtime:loaded", {
80572
- runtimeId: OPENCLAW_RUNTIME_ID,
80573
- version: OPENCLAW_RUNTIME_VERSION,
80574
- binaryAvailable: probe.available,
80575
- binaryPath: probe.binaryPath ?? config.binaryPath
80576
- });
80577
- },
80578
- onUnload: () => {
80579
- }
80580
- },
80581
- runtime: {
80582
- metadata: openclawRuntimeMetadata,
80583
- factory: openclawRuntimeFactory
80584
- }
80585
- });
80586
- }
80587
- });
80588
-
80589
80632
  // ../../plugins/fusion-plugin-paperclip-runtime/dist/paperclip-client.js
80590
80633
  function normalizeApiUrl(url) {
80591
80634
  return url.replace(/\/+$/, "");
80592
80635
  }
80593
- function buildUrl(apiUrl, path, query) {
80636
+ function buildUrl(apiUrl, path2, query) {
80594
80637
  const base = normalizeApiUrl(apiUrl);
80595
- const normalizedPath = path.startsWith("/") ? path : `/${path}`;
80638
+ const normalizedPath = path2.startsWith("/") ? path2 : `/${path2}`;
80596
80639
  const qs = query && query.size > 0 ? `?${query.toString()}` : "";
80597
80640
  return `${base}/api${normalizedPath}${qs}`;
80598
80641
  }
@@ -80629,9 +80672,9 @@ function toErrorMessage(status, statusText, body, raw) {
80629
80672
  return raw.slice(0, 200).trim();
80630
80673
  return `${status} ${statusText}`.trim();
80631
80674
  }
80632
- async function request(apiUrl, path, options) {
80675
+ async function request(apiUrl, path2, options) {
80633
80676
  const method = options?.method ?? "GET";
80634
- const url = buildUrl(apiUrl, path, options?.query);
80677
+ const url = buildUrl(apiUrl, path2, options?.query);
80635
80678
  const headers = buildHeaders(options?.apiKey);
80636
80679
  let bodyStr;
80637
80680
  if (options && "body" in options && options.body !== void 0) {
@@ -80648,7 +80691,7 @@ async function request(apiUrl, path, options) {
80648
80691
  const { value, raw } = await parseJsonBody(response);
80649
80692
  if (!response.ok) {
80650
80693
  const msg = toErrorMessage(response.status, response.statusText, value, raw);
80651
- const full = `Paperclip API ${response.status} (${method} ${path}): ${msg}`;
80694
+ const full = `Paperclip API ${response.status} (${method} ${path2}): ${msg}`;
80652
80695
  if (response.status === 409)
80653
80696
  throw new ConflictError(full);
80654
80697
  throw new Error(full);
@@ -80694,9 +80737,9 @@ function resolvePaperclipConfig(settings) {
80694
80737
  }
80695
80738
  async function discoverPaperclipCliConfig(opts = {}) {
80696
80739
  const fs = await import("node:fs/promises");
80697
- const path = await import("node:path");
80698
- const os2 = await import("node:os");
80699
- const configPath = opts.configPath ?? path.join(os2.homedir(), ".paperclip", "instances", "default", "config.json");
80740
+ const path2 = await import("node:path");
80741
+ const os3 = await import("node:os");
80742
+ const configPath = opts.configPath ?? path2.join(os3.homedir(), ".paperclip", "instances", "default", "config.json");
80700
80743
  let raw;
80701
80744
  try {
80702
80745
  raw = await fs.readFile(configPath, "utf-8");
@@ -80843,6 +80886,124 @@ async function probePaperclipConnection(opts) {
80843
80886
  }
80844
80887
  return { available: true, apiUrl, identity, probeDurationMs };
80845
80888
  }
80889
+ function stripAnsi2(str) {
80890
+ return str.replace(/\x1B\[[0-9;]*[mGKJHFABCDSTsu]/g, "");
80891
+ }
80892
+ function remapSpawnError(err, bin) {
80893
+ const code = err?.code;
80894
+ if (code === "ENOENT") {
80895
+ return new Error(`paperclipai binary not found at ${bin}; install via \`npm i -g paperclipai\``);
80896
+ }
80897
+ return err instanceof Error ? err : new Error(String(err));
80898
+ }
80899
+ async function spawnPaperclipCliJson(args, opts) {
80900
+ const { spawn: spawn10 } = await import("node:child_process");
80901
+ const bin = opts.cliBinaryPath ?? "paperclipai";
80902
+ const fullArgs = [...args, "--json"];
80903
+ if (opts.cliConfigPath) {
80904
+ fullArgs.push("--config", opts.cliConfigPath);
80905
+ }
80906
+ const timeoutMs = opts.cliTimeoutMs ?? 15e3;
80907
+ const label = ["paperclipai", ...args].join(" ");
80908
+ return new Promise((resolve17, reject) => {
80909
+ let child;
80910
+ try {
80911
+ child = spawn10(bin, fullArgs, { stdio: ["ignore", "pipe", "pipe"] });
80912
+ } catch (err) {
80913
+ reject(remapSpawnError(err, bin));
80914
+ return;
80915
+ }
80916
+ const stdoutChunks = [];
80917
+ const stderrLines = [];
80918
+ let killed = false;
80919
+ const timer = setTimeout(() => {
80920
+ killed = true;
80921
+ child.kill("SIGKILL");
80922
+ reject(new Error(`${label} timed out after ${timeoutMs}ms`));
80923
+ }, timeoutMs);
80924
+ child.stdout?.on("data", (chunk) => {
80925
+ stdoutChunks.push(chunk);
80926
+ });
80927
+ child.stderr?.on("data", (chunk) => {
80928
+ const lines = chunk.toString("utf-8").split("\n");
80929
+ for (const line of lines) {
80930
+ const stripped = stripAnsi2(line).trim();
80931
+ if (stripped)
80932
+ stderrLines.push(stripped);
80933
+ }
80934
+ });
80935
+ child.on("error", (err) => {
80936
+ clearTimeout(timer);
80937
+ reject(remapSpawnError(err, bin));
80938
+ });
80939
+ child.on("close", (code) => {
80940
+ clearTimeout(timer);
80941
+ if (killed)
80942
+ return;
80943
+ const cleaned = stripAnsi2(Buffer.concat(stdoutChunks).toString("utf-8")).trim();
80944
+ if (code !== 0) {
80945
+ const lastErr = stderrLines.filter(Boolean).pop() ?? "";
80946
+ reject(new Error(lastErr ? `${label} exited ${code}: ${lastErr}` : `${label} exited ${code}`));
80947
+ return;
80948
+ }
80949
+ if (!cleaned) {
80950
+ reject(new Error(`${label} produced no output`));
80951
+ return;
80952
+ }
80953
+ try {
80954
+ resolve17(JSON.parse(cleaned));
80955
+ } catch {
80956
+ reject(new Error(`${label} returned non-JSON output: ${cleaned.slice(0, 200)}`));
80957
+ }
80958
+ });
80959
+ });
80960
+ }
80961
+ async function createIssueViaCli(opts) {
80962
+ const args = ["issue", "create", "--company-id", opts.companyId];
80963
+ args.push("--title", opts.body.title);
80964
+ if (opts.body.description)
80965
+ args.push("--description", opts.body.description);
80966
+ if (opts.body.status)
80967
+ args.push("--status", opts.body.status);
80968
+ if (opts.body.assigneeAgentId)
80969
+ args.push("--assignee-agent-id", opts.body.assigneeAgentId);
80970
+ if (opts.body.parentId)
80971
+ args.push("--parent-id", opts.body.parentId);
80972
+ if (opts.body.projectId)
80973
+ args.push("--project-id", opts.body.projectId);
80974
+ if (opts.body.goalId)
80975
+ args.push("--goal-id", opts.body.goalId);
80976
+ const raw = await spawnPaperclipCliJson(args, opts);
80977
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
80978
+ throw new Error(`paperclipai issue create returned unexpected payload: ${JSON.stringify(raw).slice(0, 200)}`);
80979
+ }
80980
+ return raw;
80981
+ }
80982
+ async function getIssueViaCli(opts) {
80983
+ const raw = await spawnPaperclipCliJson(["issue", "get", opts.issueId], opts);
80984
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
80985
+ throw new Error(`paperclipai issue get returned unexpected payload: ${JSON.stringify(raw).slice(0, 200)}`);
80986
+ }
80987
+ return raw;
80988
+ }
80989
+ async function agentsMeViaCli(opts) {
80990
+ const raw = await spawnPaperclipCliJson(["agent", "get", opts.agentId], opts);
80991
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
80992
+ throw new Error(`paperclipai agent get returned unexpected payload: ${JSON.stringify(raw).slice(0, 200)}`);
80993
+ }
80994
+ const id = typeof raw.id === "string" ? raw.id : void 0;
80995
+ const cId = typeof raw.companyId === "string" ? raw.companyId : void 0;
80996
+ if (!id || !cId) {
80997
+ throw new Error("paperclipai agent get returned a response missing `id` or `companyId`");
80998
+ }
80999
+ return {
81000
+ agentId: id,
81001
+ agentName: typeof raw.name === "string" ? raw.name : id,
81002
+ role: typeof raw.role === "string" ? raw.role : void 0,
81003
+ companyId: cId,
81004
+ companyName: typeof raw.companyName === "string" ? raw.companyName : void 0
81005
+ };
81006
+ }
80846
81007
  var ConflictError;
80847
81008
  var init_paperclip_client = __esm({
80848
81009
  "../../plugins/fusion-plugin-paperclip-runtime/dist/paperclip-client.js"() {
@@ -80949,12 +81110,24 @@ var init_runtime_adapter3 = __esm({
80949
81110
  let companyId = this.config.companyId;
80950
81111
  if (!agentId || !companyId) {
80951
81112
  try {
80952
- const me = await agentsMe(effectiveApiUrl, effectiveApiKey);
80953
- agentId = agentId ?? me.agentId;
80954
- companyId = companyId ?? me.companyId;
81113
+ if (this.config.transport === "cli") {
81114
+ if (!agentId) {
81115
+ throw new Error("agentId is required in Local CLI mode (paperclipai has no `agents/me` equivalent \u2014 pick an agent in settings)");
81116
+ }
81117
+ const me = await agentsMeViaCli({
81118
+ agentId,
81119
+ cliBinaryPath: this.config.cliBinaryPath,
81120
+ cliConfigPath: this.config.cliConfigPath
81121
+ });
81122
+ companyId = companyId ?? me.companyId;
81123
+ } else {
81124
+ const me = await agentsMe(effectiveApiUrl, effectiveApiKey);
81125
+ agentId = agentId ?? me.agentId;
81126
+ companyId = companyId ?? me.companyId;
81127
+ }
80955
81128
  } catch (error) {
80956
81129
  const reason = error instanceof Error ? error.message : String(error);
80957
- throw new Error(`Paperclip runtime could not derive agentId/companyId from /agents/me. Configure them explicitly or check the API key. Underlying error: ${reason}`);
81130
+ throw new Error(`Paperclip runtime could not derive agentId/companyId. Configure them explicitly or check the API key / CLI auth. Underlying error: ${reason}`);
80958
81131
  }
80959
81132
  }
80960
81133
  if (!agentId || !companyId) {
@@ -80973,6 +81146,9 @@ var init_runtime_adapter3 = __esm({
80973
81146
  projectId: this.config.projectId,
80974
81147
  goalId: this.config.goalId,
80975
81148
  issueId: void 0,
81149
+ transport: this.config.transport ?? "api",
81150
+ cliBinaryPath: this.config.cliBinaryPath,
81151
+ cliConfigPath: this.config.cliConfigPath,
80976
81152
  turnIndex: 0,
80977
81153
  runTimeoutMs: this.config.runTimeoutMs ?? 6e5,
80978
81154
  pollIntervalMs: this.config.pollIntervalMs ?? 500,
@@ -81043,7 +81219,11 @@ var init_runtime_adapter3 = __esm({
81043
81219
  let finalText = stream.text;
81044
81220
  if (issueId) {
81045
81221
  try {
81046
- const issue = await getIssue(session.apiUrl, session.apiKey, issueId);
81222
+ const issue = session.transport === "cli" ? await getIssueViaCli({
81223
+ issueId,
81224
+ cliBinaryPath: session.cliBinaryPath,
81225
+ cliConfigPath: session.cliConfigPath
81226
+ }) : await getIssue(session.apiUrl, session.apiKey, issueId);
81047
81227
  issueStatus = asString2(issue.status) ?? void 0;
81048
81228
  if (!finalText) {
81049
81229
  const comments = await getIssueComments(session.apiUrl, session.apiKey, issueId);
@@ -81079,7 +81259,7 @@ var init_runtime_adapter3 = __esm({
81079
81259
  // Internals
81080
81260
  // ---------------------------------------------------------------------
81081
81261
  async createIssueForPrompt(session, prompt) {
81082
- const created = await createIssue(session.apiUrl, session.apiKey, session.companyId, {
81262
+ const body = {
81083
81263
  title: deriveIssueTitle(prompt),
81084
81264
  description: buildIssueDescription(session, prompt),
81085
81265
  status: "todo",
@@ -81087,7 +81267,13 @@ var init_runtime_adapter3 = __esm({
81087
81267
  ...session.parentIssueId ? { parentId: session.parentIssueId } : {},
81088
81268
  ...session.projectId ? { projectId: session.projectId } : {},
81089
81269
  ...session.goalId ? { goalId: session.goalId } : {}
81090
- });
81270
+ };
81271
+ const created = session.transport === "cli" ? await createIssueViaCli({
81272
+ companyId: session.companyId,
81273
+ body,
81274
+ cliBinaryPath: session.cliBinaryPath,
81275
+ cliConfigPath: session.cliConfigPath
81276
+ }) : await createIssue(session.apiUrl, session.apiKey, session.companyId, body);
81091
81277
  return pickIssueId(created);
81092
81278
  }
81093
81279
  async streamRunEvents(session, runId) {
@@ -81387,7 +81573,7 @@ async function initPromptOverrides() {
81387
81573
  promptOverridesReady = true;
81388
81574
  }
81389
81575
  }
81390
- var upload, resolveWorkflowStepRefinePrompt, promptOverridesReady, DEFAULT_WORKFLOW_STEP_REFINE_PROMPT, DEFAULT_AUTOMATION_TIMEOUT_MS, AUTOMATION_MAX_BUFFER, MANUAL_RUN_AI_SYSTEM_PROMPT;
81576
+ var BUNDLED_PLUGIN_RUNTIMES, upload, resolveWorkflowStepRefinePrompt, promptOverridesReady, DEFAULT_WORKFLOW_STEP_REFINE_PROMPT, DEFAULT_AUTOMATION_TIMEOUT_MS, AUTOMATION_MAX_BUFFER, MANUAL_RUN_AI_SYSTEM_PROMPT;
81391
81577
  var init_routes = __esm({
81392
81578
  "../dashboard/src/routes.ts"() {
81393
81579
  "use strict";
@@ -81401,6 +81587,8 @@ var init_routes = __esm({
81401
81587
  init_sse_buffer();
81402
81588
  init_api_error();
81403
81589
  init_plugin_routes();
81590
+ init_dist();
81591
+ init_dist2();
81404
81592
  init_ai_session_diagnostics();
81405
81593
  init_context();
81406
81594
  init_register_task_workflow_routes();
@@ -81434,6 +81622,29 @@ var init_routes = __esm({
81434
81622
  init_register_git_github();
81435
81623
  init_src2();
81436
81624
  init_resolve_diff_base();
81625
+ BUNDLED_PLUGIN_RUNTIMES = [
81626
+ {
81627
+ pluginId: "fusion-plugin-hermes-runtime",
81628
+ runtimeId: hermesRuntimeMetadata.runtimeId,
81629
+ name: hermesRuntimeMetadata.name,
81630
+ ...hermesRuntimeMetadata.description ? { description: hermesRuntimeMetadata.description } : {},
81631
+ version: hermesRuntimeMetadata.version ?? "0.0.0"
81632
+ },
81633
+ {
81634
+ pluginId: "fusion-plugin-openclaw-runtime",
81635
+ runtimeId: openclawRuntimeMetadata.runtimeId,
81636
+ name: openclawRuntimeMetadata.name,
81637
+ ...openclawRuntimeMetadata.description ? { description: openclawRuntimeMetadata.description } : {},
81638
+ version: openclawRuntimeMetadata.version ?? "0.0.0"
81639
+ },
81640
+ {
81641
+ pluginId: "fusion-plugin-paperclip-runtime",
81642
+ runtimeId: "paperclip",
81643
+ name: "Paperclip Runtime",
81644
+ description: "Drives a Paperclip agent via the wakeup + heartbeat-run REST API",
81645
+ version: "1.0.0"
81646
+ }
81647
+ ];
81437
81648
  upload = multer({
81438
81649
  storage: multer.memoryStorage(),
81439
81650
  limits: { fileSize: 5 * 1024 * 1024 }
@@ -86172,9 +86383,9 @@ async function fetchGitHubIssues(owner, repo, options = {}) {
86172
86383
  if (since) {
86173
86384
  params.append("since", since);
86174
86385
  }
86175
- const path = `repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues?${params.toString()}`;
86386
+ const path2 = `repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues?${params.toString()}`;
86176
86387
  try {
86177
- const issues = await runGhJsonAsync(["api", path]);
86388
+ const issues = await runGhJsonAsync(["api", path2]);
86178
86389
  return issues.filter((issue) => !issue.pull_request).slice(0, limit);
86179
86390
  } catch (error) {
86180
86391
  throw new Error(getGhErrorMessage(error));
@@ -86834,7 +87045,8 @@ async function runSkillsInstall(args, options) {
86834
87045
  npxArgs.push("-y", "-a", "pi");
86835
87046
  const child = spawn8("npx", npxArgs, {
86836
87047
  cwd: process.cwd(),
86837
- stdio: "inherit"
87048
+ stdio: "inherit",
87049
+ shell: true
86838
87050
  });
86839
87051
  const exitCode = await new Promise((resolve17, reject) => {
86840
87052
  child.on("exit", (code) => {
@@ -86929,9 +87141,9 @@ async function fetchGitHubIssuesViaGh(owner, repo, options = {}) {
86929
87141
  if (options.labels && options.labels.length > 0) {
86930
87142
  queryParams.append("labels", options.labels.join(","));
86931
87143
  }
86932
- const path = `repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues?${queryParams.toString()}`;
87144
+ const path2 = `repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues?${queryParams.toString()}`;
86933
87145
  try {
86934
- const issues = await runGhJsonAsync(["api", path]);
87146
+ const issues = await runGhJsonAsync(["api", path2]);
86935
87147
  return issues.filter((issue) => !issue.pull_request);
86936
87148
  } catch (error) {
86937
87149
  throw new Error(getGhErrorMessage(error));
@@ -86939,9 +87151,9 @@ async function fetchGitHubIssuesViaGh(owner, repo, options = {}) {
86939
87151
  }
86940
87152
  async function fetchGitHubIssueViaGh(owner, repo, issueNumber) {
86941
87153
  ensureGhCliAuth();
86942
- const path = `repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${issueNumber}`;
87154
+ const path2 = `repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${issueNumber}`;
86943
87155
  try {
86944
- return await runGhJsonAsync(["api", path]);
87156
+ return await runGhJsonAsync(["api", path2]);
86945
87157
  } catch (error) {
86946
87158
  throw new Error(getGhErrorMessage(error));
86947
87159
  }
@@ -88285,7 +88497,8 @@ Status: ${updated.status}`
88285
88497
  npxArgs.push("-y", "-a", "pi");
88286
88498
  const child = spawn9("npx", npxArgs, {
88287
88499
  cwd: resolveProjectRoot(ctx.cwd),
88288
- stdio: "pipe"
88500
+ stdio: "pipe",
88501
+ shell: true
88289
88502
  });
88290
88503
  let stderr = "";
88291
88504
  child.stdout?.on("data", () => {
@@ -88368,7 +88581,8 @@ Status: ${updated.status}`
88368
88581
  cwd: resolveProjectRoot(ctx.cwd),
88369
88582
  stdio: ["ignore", "pipe", "pipe"],
88370
88583
  detached: false,
88371
- env: { ...process.env }
88584
+ env: { ...process.env },
88585
+ shell: true
88372
88586
  });
88373
88587
  dashboardProcess = child;
88374
88588
  dashboardPort = port;