@opengoat/core 2026.2.13 → 2026.2.14-3

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 (30) hide show
  1. package/dist/core/agents/application/agent.service.d.ts +2 -0
  2. package/dist/core/agents/application/agent.service.js +67 -25
  3. package/dist/core/agents/application/agent.service.js.map +1 -1
  4. package/dist/core/bootstrap/application/bootstrap.service.d.ts +4 -0
  5. package/dist/core/bootstrap/application/bootstrap.service.js +28 -1
  6. package/dist/core/bootstrap/application/bootstrap.service.js.map +1 -1
  7. package/dist/core/domain/opengoat-paths.d.ts +1 -0
  8. package/dist/core/opengoat/application/opengoat.service.d.ts +7 -0
  9. package/dist/core/opengoat/application/opengoat.service.helpers.d.ts +52 -0
  10. package/dist/core/opengoat/application/opengoat.service.helpers.js +325 -0
  11. package/dist/core/opengoat/application/opengoat.service.helpers.js.map +1 -0
  12. package/dist/core/opengoat/application/opengoat.service.js +83 -289
  13. package/dist/core/opengoat/application/opengoat.service.js.map +1 -1
  14. package/dist/core/providers/application/provider.service.d.ts +1 -0
  15. package/dist/core/providers/application/provider.service.js +63 -1
  16. package/dist/core/providers/application/provider.service.js.map +1 -1
  17. package/dist/core/templates/assets/ceo/BOOTSTRAP.md +41 -0
  18. package/dist/core/templates/assets/ceo/ROLE.md +2 -0
  19. package/dist/core/templates/assets/organization/MISSION.md +73 -0
  20. package/dist/core/templates/assets/organization/STRATEGY.md +107 -0
  21. package/dist/core/templates/assets/organization/VISION.md +80 -0
  22. package/dist/core/templates/assets/organization/wiki/index.md +15 -0
  23. package/dist/core/templates/default-templates.d.ts +6 -1
  24. package/dist/core/templates/default-templates.js +52 -5
  25. package/dist/core/templates/default-templates.js.map +1 -1
  26. package/dist/platform/node/node-path.port.js +1 -0
  27. package/dist/platform/node/node-path.port.js.map +1 -1
  28. package/package.json +1 -1
  29. package/dist/core/templates/assets/ceo/AGENTS.md +0 -20
  30. package/dist/core/templates/assets/ceo/SOUL.md +0 -15
@@ -1,5 +1,3 @@
1
- import path from "node:path";
2
- import { homedir } from "node:os";
3
1
  import { AgentManifestService } from "../../agents/application/agent-manifest.service.js";
4
2
  import { AgentService } from "../../agents/application/agent.service.js";
5
3
  import { BoardService, } from "../../boards/index.js";
@@ -11,6 +9,7 @@ import { ProviderService } from "../../providers/application/provider.service.js
11
9
  import { ProviderCommandNotFoundError, createDefaultProviderRegistry, } from "../../providers/index.js";
12
10
  import { SessionService, } from "../../sessions/index.js";
13
11
  import { SkillService, } from "../../skills/index.js";
12
+ import { assertAgentExists, buildBlockedTaskMessage, buildInactiveAgentMessage, buildInactiveSessionRef, buildReporteeStats, buildTaskSessionRef, buildTodoTaskMessage, collectAllReportees, containsAgentNotFoundMessage, containsAlreadyExistsMessage, extractManagedSkillsDir, extractOpenClawAgentEntry, extractOpenClawAgents, isSpawnPermissionOrMissing, pathIsWithin, pathMatches, prepareOpenClawCommandEnv, resolveInactiveAgentNotificationTarget, resolveInactiveMinutes, toErrorMessage, } from "./opengoat.service.helpers.js";
14
13
  const OPENCLAW_PROVIDER_ID = "openclaw";
15
14
  const OPENCLAW_DEFAULT_AGENT_ID = "main";
16
15
  export class OpenGoatService {
@@ -51,6 +50,7 @@ export class OpenGoatService {
51
50
  });
52
51
  this.bootstrapService = new BootstrapService({
53
52
  fileSystem: deps.fileSystem,
53
+ pathPort: deps.pathPort,
54
54
  pathsProvider: deps.pathsProvider,
55
55
  agentService: this.agentService,
56
56
  nowIso,
@@ -107,6 +107,7 @@ export class OpenGoatService {
107
107
  }
108
108
  candidateOpenClawAgentIds.add(agent.id);
109
109
  }
110
+ await this.addWorkspaceAgentCandidates(paths, candidateOpenClawAgentIds, warnings);
110
111
  try {
111
112
  const openClawAgents = await this.listOpenClawAgents(paths);
112
113
  for (const entry of openClawAgents) {
@@ -388,12 +389,13 @@ export class OpenGoatService {
388
389
  this.agentService.listAgents(paths),
389
390
  this.agentManifestService.listManifests(paths),
390
391
  ]);
392
+ const reporteeStats = buildReporteeStats(manifests);
391
393
  const descriptorsById = new Map(agents.map((agent) => [agent.id, agent]));
392
394
  const agent = descriptorsById.get(agentId);
393
395
  if (!agent) {
394
396
  throw new Error(`Agent "${agentId}" does not exist.`);
395
397
  }
396
- const totalReportees = collectAllReportees(manifests, agentId).length;
398
+ const totalReportees = reporteeStats.totalByManager.get(agentId) ?? 0;
397
399
  const directReportees = manifests
398
400
  .filter((manifest) => manifest.metadata.reportsTo === agentId)
399
401
  .map((manifest) => {
@@ -406,8 +408,7 @@ export class OpenGoatService {
406
408
  id: manifest.agentId,
407
409
  name,
408
410
  role,
409
- totalReportees: collectAllReportees(manifests, manifest.agentId)
410
- .length,
411
+ totalReportees: reporteeStats.totalByManager.get(manifest.agentId) ?? 0,
411
412
  };
412
413
  })
413
414
  .sort((left, right) => left.id.localeCompare(right.id));
@@ -505,12 +506,37 @@ export class OpenGoatService {
505
506
  const paths = this.pathsProvider.getPaths();
506
507
  const ranAt = this.resolveNowIso();
507
508
  const manifests = await this.agentManifestService.listManifests(paths);
508
- const manifestsById = new Map(manifests.map((manifest) => [manifest.agentId, manifest]));
509
509
  const inactiveMinutes = resolveInactiveMinutes(options.inactiveMinutes);
510
- const inactiveCandidates = await this.collectInactiveAgents(paths, manifests, inactiveMinutes);
510
+ const notificationTarget = resolveInactiveAgentNotificationTarget(options.notificationTarget);
511
+ const notifyInactiveAgents = options.notifyInactiveAgents ?? true;
512
+ const inactiveCandidates = notifyInactiveAgents
513
+ ? await this.collectInactiveAgents(paths, manifests, inactiveMinutes, notificationTarget)
514
+ : [];
515
+ const latestCeoProjectPath = notifyInactiveAgents
516
+ ? await this.resolveLatestProjectPathForAgent(paths, DEFAULT_AGENT_ID)
517
+ : undefined;
511
518
  const tasks = await this.boardService.listTasks(paths, { limit: 10_000 });
519
+ const taskStatusDispatch = await this.dispatchTaskStatusAutomations(paths, tasks, manifests);
520
+ const inactiveDispatches = await this.dispatchInactiveAgentAutomations(paths, inactiveCandidates, inactiveMinutes, latestCeoProjectPath);
521
+ const dispatches = [
522
+ ...taskStatusDispatch.dispatches,
523
+ ...inactiveDispatches,
524
+ ];
525
+ const failed = dispatches.filter((entry) => !entry.ok).length;
526
+ return {
527
+ ranAt,
528
+ scannedTasks: tasks.length,
529
+ todoTasks: taskStatusDispatch.todoTasks,
530
+ blockedTasks: taskStatusDispatch.blockedTasks,
531
+ inactiveAgents: inactiveCandidates.length,
532
+ sent: dispatches.length - failed,
533
+ failed,
534
+ dispatches,
535
+ };
536
+ }
537
+ async dispatchTaskStatusAutomations(paths, tasks, manifests) {
538
+ const manifestsById = new Map(manifests.map((manifest) => [manifest.agentId, manifest]));
512
539
  const dispatches = [];
513
- let scannedTasks = tasks.length;
514
540
  let todoTasks = 0;
515
541
  let blockedTasks = 0;
516
542
  for (const task of tasks) {
@@ -549,6 +575,14 @@ export class OpenGoatService {
549
575
  error: result.error,
550
576
  });
551
577
  }
578
+ return {
579
+ dispatches,
580
+ todoTasks,
581
+ blockedTasks,
582
+ };
583
+ }
584
+ async dispatchInactiveAgentAutomations(paths, inactiveCandidates, inactiveMinutes, latestCeoProjectPath) {
585
+ const dispatches = [];
552
586
  for (const candidate of inactiveCandidates) {
553
587
  const sessionRef = buildInactiveSessionRef(candidate.managerAgentId, candidate.subjectAgentId);
554
588
  const message = buildInactiveAgentMessage({
@@ -556,10 +590,14 @@ export class OpenGoatService {
556
590
  subjectAgentId: candidate.subjectAgentId,
557
591
  subjectName: candidate.subjectName,
558
592
  role: candidate.role,
593
+ directReporteesCount: candidate.directReporteesCount,
594
+ indirectReporteesCount: candidate.indirectReporteesCount,
559
595
  inactiveMinutes,
560
596
  lastActionTimestamp: candidate.lastActionTimestamp,
561
597
  });
562
- const result = await this.dispatchAutomationMessage(paths, candidate.managerAgentId, sessionRef, message);
598
+ const result = await this.dispatchAutomationMessage(paths, candidate.managerAgentId, sessionRef, message, {
599
+ cwd: latestCeoProjectPath,
600
+ });
563
601
  dispatches.push({
564
602
  kind: "inactive",
565
603
  targetAgentId: candidate.managerAgentId,
@@ -569,17 +607,7 @@ export class OpenGoatService {
569
607
  error: result.error,
570
608
  });
571
609
  }
572
- const failed = dispatches.filter((entry) => !entry.ok).length;
573
- return {
574
- ranAt,
575
- scannedTasks,
576
- todoTasks,
577
- blockedTasks,
578
- inactiveAgents: inactiveCandidates.length,
579
- sent: dispatches.length - failed,
580
- failed,
581
- dispatches,
582
- };
610
+ return dispatches;
583
611
  }
584
612
  async listSkills(agentId = DEFAULT_AGENT_ID) {
585
613
  const paths = this.pathsProvider.getPaths();
@@ -673,11 +701,12 @@ export class OpenGoatService {
673
701
  getPaths() {
674
702
  return this.pathsProvider.getPaths();
675
703
  }
676
- async dispatchAutomationMessage(paths, agentId, sessionRef, message) {
704
+ async dispatchAutomationMessage(paths, agentId, sessionRef, message, options = {}) {
677
705
  try {
678
706
  const result = await this.orchestrationService.runAgent(paths, agentId, {
679
707
  message,
680
708
  sessionRef,
709
+ cwd: options.cwd,
681
710
  env: process.env,
682
711
  });
683
712
  if (result.code !== 0) {
@@ -834,6 +863,21 @@ export class OpenGoatService {
834
863
  }
835
864
  return extractOpenClawAgents(parsed);
836
865
  }
866
+ async addWorkspaceAgentCandidates(paths, candidates, warnings) {
867
+ try {
868
+ const workspaceDirs = await this.fileSystem.listDirectories(paths.workspacesDir);
869
+ for (const workspaceDir of workspaceDirs) {
870
+ const workspaceAgentId = normalizeAgentId(workspaceDir);
871
+ if (workspaceAgentId &&
872
+ workspaceAgentId !== OPENCLAW_DEFAULT_AGENT_ID) {
873
+ candidates.add(workspaceAgentId);
874
+ }
875
+ }
876
+ }
877
+ catch (error) {
878
+ warnings.push(`Workspace fallback discovery failed: ${toErrorMessage(error)}`);
879
+ }
880
+ }
837
881
  async ensureOpenClawAgentLocation(paths, params) {
838
882
  if (!this.commandRunner) {
839
883
  return;
@@ -882,297 +926,47 @@ export class OpenGoatService {
882
926
  ...process.env,
883
927
  };
884
928
  }
885
- async collectInactiveAgents(paths, manifests, inactiveMinutes) {
929
+ async collectInactiveAgents(paths, manifests, inactiveMinutes, notificationTarget) {
886
930
  const nowMs = this.resolveNowMs();
887
931
  const inactiveCutoffMs = nowMs - inactiveMinutes * 60_000;
932
+ const reporteeStats = buildReporteeStats(manifests);
888
933
  const inactive = [];
889
934
  for (const manifest of manifests) {
890
935
  const managerAgentId = normalizeAgentId(manifest.metadata.reportsTo ?? "");
891
936
  if (!managerAgentId) {
892
937
  continue;
893
938
  }
939
+ if (notificationTarget === "ceo-only" &&
940
+ managerAgentId !== DEFAULT_AGENT_ID) {
941
+ continue;
942
+ }
894
943
  const lastAction = await this.sessionService.getLastAgentAction(paths, manifest.agentId);
895
944
  if (lastAction && lastAction.timestamp >= inactiveCutoffMs) {
896
945
  continue;
897
946
  }
947
+ const directReporteesCount = reporteeStats.directByManager.get(manifest.agentId) ?? 0;
948
+ const totalReporteesCount = reporteeStats.totalByManager.get(manifest.agentId) ?? 0;
949
+ const indirectReporteesCount = Math.max(0, totalReporteesCount - directReporteesCount);
898
950
  inactive.push({
899
951
  managerAgentId,
900
952
  subjectAgentId: manifest.agentId,
901
953
  subjectName: manifest.metadata.name,
902
954
  role: manifest.metadata.description,
955
+ directReporteesCount,
956
+ indirectReporteesCount,
903
957
  lastActionTimestamp: lastAction?.timestamp,
904
958
  });
905
959
  }
906
960
  return inactive;
907
961
  }
908
- }
909
- function containsAlreadyExistsMessage(stdout, stderr) {
910
- const text = `${stdout}\n${stderr}`.toLowerCase();
911
- return /\balready exists?\b/.test(text);
912
- }
913
- function containsAgentNotFoundMessage(stdout, stderr) {
914
- const text = `${stdout}\n${stderr}`.toLowerCase();
915
- return /\b(not found|does not exist|no such agent|unknown agent|could not find|no agent found|not exist)\b/.test(text);
916
- }
917
- function toErrorMessage(error) {
918
- if (error instanceof Error) {
919
- return error.message;
920
- }
921
- return String(error);
922
- }
923
- function resolveInactiveMinutes(value) {
924
- if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
925
- return 30;
926
- }
927
- return Math.floor(value);
928
- }
929
- function extractManagedSkillsDir(payload) {
930
- if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
931
- return null;
932
- }
933
- const record = payload;
934
- if (typeof record.managedSkillsDir !== "string") {
935
- return null;
936
- }
937
- const managedSkillsDir = record.managedSkillsDir.trim();
938
- return managedSkillsDir || null;
939
- }
940
- function extractOpenClawAgents(payload) {
941
- if (!Array.isArray(payload)) {
942
- return [];
943
- }
944
- const entries = [];
945
- for (const entry of payload) {
946
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
947
- continue;
948
- }
949
- const record = entry;
950
- const id = normalizeAgentId(String(record.id ?? ""));
951
- if (!id) {
952
- continue;
953
- }
954
- entries.push({
955
- id,
956
- workspace: typeof record.workspace === "string" ? record.workspace : "",
957
- agentDir: typeof record.agentDir === "string" ? record.agentDir : "",
958
- });
959
- }
960
- return entries;
961
- }
962
- function extractOpenClawAgentEntry(payload, agentId) {
963
- const normalizedAgentId = normalizeAgentId(agentId);
964
- if (!normalizedAgentId) {
965
- return null;
966
- }
967
- for (const entry of extractOpenClawAgents(payload)) {
968
- if (entry.id !== normalizedAgentId) {
969
- continue;
962
+ async resolveLatestProjectPathForAgent(paths, rawAgentId) {
963
+ const agentId = normalizeAgentId(rawAgentId);
964
+ if (!agentId) {
965
+ return undefined;
970
966
  }
971
- return {
972
- workspace: entry.workspace,
973
- agentDir: entry.agentDir,
974
- };
975
- }
976
- return null;
977
- }
978
- function pathMatches(left, right) {
979
- const leftNormalized = normalizePathForCompare(left);
980
- const rightNormalized = normalizePathForCompare(right);
981
- if (!leftNormalized || !rightNormalized) {
982
- return false;
983
- }
984
- return leftNormalized === rightNormalized;
985
- }
986
- function pathIsWithin(containerPath, candidatePath) {
987
- const normalizedContainer = normalizePathForCompare(containerPath);
988
- const normalizedCandidate = normalizePathForCompare(candidatePath);
989
- if (!normalizedContainer || !normalizedCandidate) {
990
- return false;
967
+ const sessions = await this.sessionService.listSessions(paths, agentId);
968
+ const latestProjectPath = sessions[0]?.projectPath?.trim();
969
+ return latestProjectPath || undefined;
991
970
  }
992
- const relative = path.relative(normalizedContainer, normalizedCandidate);
993
- if (!relative) {
994
- return true;
995
- }
996
- return !relative.startsWith("..") && !path.isAbsolute(relative);
997
- }
998
- function normalizePathForCompare(value) {
999
- const trimmed = value.trim();
1000
- if (!trimmed) {
1001
- return "";
1002
- }
1003
- const resolved = path.resolve(trimmed);
1004
- if (process.platform === "win32") {
1005
- return resolved.toLowerCase();
1006
- }
1007
- return resolved;
1008
- }
1009
- function buildTaskSessionRef(agentId, taskId) {
1010
- const normalizedAgentId = normalizeAgentId(agentId) || DEFAULT_AGENT_ID;
1011
- const normalizedTaskId = normalizeAgentId(taskId) || "task";
1012
- return `agent:${normalizedAgentId}:agent_${normalizedAgentId}_task_${normalizedTaskId}`;
1013
- }
1014
- function buildInactiveSessionRef(managerAgentId, subjectAgentId) {
1015
- const manager = normalizeAgentId(managerAgentId) || DEFAULT_AGENT_ID;
1016
- const subject = normalizeAgentId(subjectAgentId) || "agent";
1017
- return `agent:${manager}:agent_${manager}_inactive_${subject}`;
1018
- }
1019
- function buildTodoTaskMessage(params) {
1020
- const blockers = params.task.blockers.length > 0 ? params.task.blockers.join("; ") : "None";
1021
- const artifacts = params.task.artifacts.length > 0
1022
- ? params.task.artifacts
1023
- .map((entry) => `- ${entry.createdAt} @${entry.createdBy}: ${entry.content}`)
1024
- .join("\n")
1025
- : "- None";
1026
- const worklog = params.task.worklog.length > 0
1027
- ? params.task.worklog
1028
- .map((entry) => `- ${entry.createdAt} @${entry.createdBy}: ${entry.content}`)
1029
- .join("\n")
1030
- : "- None";
1031
- return [
1032
- `Task #${params.task.taskId} is assigned to you and currently in TODO. Please work on it now.`,
1033
- "",
1034
- `Task ID: ${params.task.taskId}`,
1035
- `Title: ${params.task.title}`,
1036
- `Description: ${params.task.description}`,
1037
- `Project: ${params.task.project}`,
1038
- `Status: ${params.task.status}`,
1039
- `Owner: @${params.task.owner}`,
1040
- `Assigned to: @${params.task.assignedTo}`,
1041
- `Created at: ${params.task.createdAt}`,
1042
- `Blockers: ${blockers}`,
1043
- "Artifacts:",
1044
- artifacts,
1045
- "Worklog:",
1046
- worklog,
1047
- ].join("\n");
1048
- }
1049
- function buildBlockedTaskMessage(params) {
1050
- const blockerReason = params.task.blockers.length > 0
1051
- ? params.task.blockers.join("; ")
1052
- : params.task.statusReason?.trim() || "no blocker details were provided";
1053
- const artifacts = params.task.artifacts.length > 0
1054
- ? params.task.artifacts
1055
- .map((entry) => `- ${entry.createdAt} @${entry.createdBy}: ${entry.content}`)
1056
- .join("\n")
1057
- : "- None";
1058
- const worklog = params.task.worklog.length > 0
1059
- ? params.task.worklog
1060
- .map((entry) => `- ${entry.createdAt} @${entry.createdBy}: ${entry.content}`)
1061
- .join("\n")
1062
- : "- None";
1063
- return [
1064
- `Task #${params.task.taskId}, assigned to your reportee "@${params.task.assignedTo}" is blocked because of ${blockerReason}. Help unblocking it.`,
1065
- "",
1066
- `Task ID: ${params.task.taskId}`,
1067
- `Title: ${params.task.title}`,
1068
- `Description: ${params.task.description}`,
1069
- `Project: ${params.task.project}`,
1070
- `Status: ${params.task.status}`,
1071
- `Owner: @${params.task.owner}`,
1072
- `Assigned to: @${params.task.assignedTo}`,
1073
- `Created at: ${params.task.createdAt}`,
1074
- "Artifacts:",
1075
- artifacts,
1076
- "Worklog:",
1077
- worklog,
1078
- ].join("\n");
1079
- }
1080
- function buildInactiveAgentMessage(params) {
1081
- const lastAction = typeof params.lastActionTimestamp === "number" &&
1082
- Number.isFinite(params.lastActionTimestamp)
1083
- ? new Date(params.lastActionTimestamp).toISOString()
1084
- : "No recorded assistant actions yet";
1085
- return [
1086
- `Your reportee "@${params.subjectAgentId}" (${params.subjectName}) has no activity in the last ${params.inactiveMinutes} minutes.`,
1087
- `Role: ${params.role}`,
1088
- `Last action: ${lastAction}`,
1089
- `Manager: @${params.managerAgentId}`,
1090
- "Please check in and unblock progress.",
1091
- ].join("\n");
1092
- }
1093
- function assertAgentExists(manifests, agentId) {
1094
- if (manifests.some((manifest) => manifest.agentId === agentId)) {
1095
- return;
1096
- }
1097
- throw new Error(`Agent "${agentId}" does not exist.`);
1098
- }
1099
- function collectAllReportees(manifests, managerAgentId) {
1100
- const byManager = new Map();
1101
- for (const manifest of manifests) {
1102
- const reportsTo = manifest.metadata.reportsTo;
1103
- if (!reportsTo) {
1104
- continue;
1105
- }
1106
- const reportees = byManager.get(reportsTo) ?? [];
1107
- reportees.push(manifest.agentId);
1108
- byManager.set(reportsTo, reportees);
1109
- }
1110
- const visited = new Set();
1111
- const queue = [...(byManager.get(managerAgentId) ?? [])];
1112
- while (queue.length > 0) {
1113
- const current = queue.shift();
1114
- if (!current || current === managerAgentId || visited.has(current)) {
1115
- continue;
1116
- }
1117
- visited.add(current);
1118
- queue.push(...(byManager.get(current) ?? []));
1119
- }
1120
- return [...visited].sort((left, right) => left.localeCompare(right));
1121
- }
1122
- function prepareOpenClawCommandEnv(env) {
1123
- const mergedPath = dedupePathEntries([
1124
- ...resolvePreferredOpenClawCommandPaths(env),
1125
- ...(env.PATH?.split(path.delimiter) ?? []),
1126
- ]);
1127
- return {
1128
- ...env,
1129
- PATH: mergedPath.join(path.delimiter),
1130
- };
1131
- }
1132
- function resolvePreferredOpenClawCommandPaths(env) {
1133
- const homeDir = homedir();
1134
- const preferredPaths = [
1135
- path.dirname(process.execPath),
1136
- path.join(homeDir, ".npm-global", "bin"),
1137
- path.join(homeDir, ".npm", "bin"),
1138
- path.join(homeDir, ".local", "bin"),
1139
- path.join(homeDir, ".volta", "bin"),
1140
- path.join(homeDir, ".fnm", "current", "bin"),
1141
- path.join(homeDir, ".asdf", "shims"),
1142
- path.join(homeDir, "bin"),
1143
- ];
1144
- const npmPrefixCandidates = dedupePathEntries([
1145
- env.npm_config_prefix ?? "",
1146
- env.NPM_CONFIG_PREFIX ?? "",
1147
- process.env.npm_config_prefix ?? "",
1148
- process.env.NPM_CONFIG_PREFIX ?? "",
1149
- ]);
1150
- for (const prefix of npmPrefixCandidates) {
1151
- preferredPaths.push(path.join(prefix, "bin"));
1152
- }
1153
- if (process.platform === "darwin") {
1154
- preferredPaths.push("/opt/homebrew/bin", "/opt/homebrew/opt/node@22/bin", "/usr/local/opt/node@22/bin");
1155
- }
1156
- return preferredPaths;
1157
- }
1158
- function dedupePathEntries(entries) {
1159
- const seen = new Set();
1160
- const deduped = [];
1161
- for (const rawEntry of entries) {
1162
- const entry = rawEntry.trim();
1163
- if (!entry || seen.has(entry)) {
1164
- continue;
1165
- }
1166
- seen.add(entry);
1167
- deduped.push(entry);
1168
- }
1169
- return deduped;
1170
- }
1171
- function isSpawnPermissionOrMissing(error) {
1172
- return (typeof error === "object" &&
1173
- error !== null &&
1174
- "code" in error &&
1175
- ((error.code ?? "") === "ENOENT" ||
1176
- (error.code ?? "") === "EACCES"));
1177
971
  }
1178
972
  //# sourceMappingURL=opengoat.service.js.map