heartbeat-opencode-plugin 0.1.1 → 0.1.2

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 (2) hide show
  1. package/package.json +1 -1
  2. package/scheduler/index.ts +38 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "heartbeat-opencode-plugin",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Heartbeat Runtime",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -75,6 +75,17 @@ const OPENCODE_FALLBACK_PATHS = [
75
75
  "/opt/homebrew/bin/opencode",
76
76
  "/usr/local/bin/opencode",
77
77
  ];
78
+ const DEFAULT_EXEC_PATH_ENTRIES = [
79
+ "/opt/homebrew/bin",
80
+ "/opt/homebrew/sbin",
81
+ "/usr/local/bin",
82
+ "/usr/local/sbin",
83
+ "/usr/bin",
84
+ "/bin",
85
+ "/usr/sbin",
86
+ "/sbin",
87
+ "/Library/Apple/usr/bin",
88
+ ];
78
89
  const OUTPUT_TAG_NOTE =
79
90
  "Runtime contract: while running Heartbeat programs, every emitted status/output line must be prefixed with [program][taskId] for grepability.";
80
91
 
@@ -161,6 +172,24 @@ function resolveOpencodeCommand(command: string): string {
161
172
  return command;
162
173
  }
163
174
 
175
+ function buildExecutablePath(): string {
176
+ const currentEntries = (process.env.PATH ?? "")
177
+ .split(path.delimiter)
178
+ .map((entry) => entry.trim())
179
+ .filter(Boolean);
180
+
181
+ const merged = [...currentEntries, ...DEFAULT_EXEC_PATH_ENTRIES];
182
+ const unique = Array.from(new Set(merged));
183
+ return unique.join(path.delimiter);
184
+ }
185
+
186
+ function buildJobEnv(): NodeJS.ProcessEnv {
187
+ return {
188
+ ...process.env,
189
+ PATH: buildExecutablePath(),
190
+ };
191
+ }
192
+
164
193
  function readJob(jobId: string): Job | null {
165
194
  const file = jobFilePath(jobId);
166
195
  if (!fs.existsSync(file)) return null;
@@ -422,6 +451,7 @@ export function runJob(jobId: string): Promise<RunResult> {
422
451
  writeJob(job);
423
452
 
424
453
  appendJobLog(job, `Starting job "${job.name}"`);
454
+ const jobEnv = buildJobEnv();
425
455
  const resolvedCommand = job.kind === "opencode"
426
456
  ? resolveOpencodeCommand(job.command)
427
457
  : job.command;
@@ -431,12 +461,13 @@ export function runJob(jobId: string): Promise<RunResult> {
431
461
  }
432
462
  appendJobLog(job, `Command: ${resolvedCommand} ${job.args.join(" ")}`);
433
463
  appendJobLog(job, `Workdir: ${job.workdir}`);
464
+ appendJobLog(job, `PATH: ${jobEnv.PATH ?? ""}`);
434
465
 
435
466
  let child: ReturnType<typeof spawn>;
436
467
  try {
437
468
  child = spawn(resolvedCommand, job.args, {
438
469
  cwd: job.workdir,
439
- env: process.env,
470
+ env: jobEnv,
440
471
  shell: false,
441
472
  stdio: ["ignore", "pipe", "pipe"],
442
473
  });
@@ -690,6 +721,7 @@ function buildCalendarXml(calendars: CalendarEntry[]): string {
690
721
  function createLaunchdPlist(job: Job): string {
691
722
  const label = getConfigLaunchdLabel(job.id);
692
723
  const parsed = parseCronToLaunchd(job.schedule);
724
+ const executablePath = buildExecutablePath();
693
725
 
694
726
  const scheduleBlock = parsed.startInterval
695
727
  ? ` <key>StartInterval</key>\n <integer>${parsed.startInterval}</integer>`
@@ -711,6 +743,11 @@ function createLaunchdPlist(job: Job): string {
711
743
  <string>run</string>
712
744
  <string>${escapeXml(job.id)}</string>
713
745
  </array>
746
+ <key>EnvironmentVariables</key>
747
+ <dict>
748
+ <key>PATH</key>
749
+ <string>${escapeXml(executablePath)}</string>
750
+ </dict>
714
751
  ${scheduleBlock}
715
752
  <key>StandardOutPath</key>
716
753
  <string>${escapeXml(sharedLogPath())}</string>