@yemi33/minions 0.1.1817 → 0.1.1819

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.
package/CHANGELOG.md CHANGED
@@ -1,15 +1,20 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1817 (2026-05-09)
3
+ ## 0.1.1819 (2026-05-09)
4
+
5
+ ### Fixes
6
+ - stop visibility=hidden beacons from racing pagehide and resurrecting closed-tab entries in dashboard-browser.json (#2275)
7
+
8
+ ## 0.1.1818 (2026-05-09)
9
+
10
+ ### Fixes
11
+ - write [process-exit] sentinel directly to live-output.log instead of bouncing it through stdout (#2266)
12
+
13
+ ## 0.1.1816 (2026-05-09)
4
14
 
5
15
  ### Features
6
- - suppress duplicate inline ask dispatch (#2256)
7
16
  - correlate CC action failures (#2254)
8
17
 
9
- ### Other
10
- - test(shared): add unit tests for project resolution and path comparison helpers (#2268)
11
- - test(cli): add unit tests for pid/dispatch helpers and help formatter (#2267)
12
-
13
18
  ## 0.1.1815 (2026-05-09)
14
19
 
15
20
  ### Features
@@ -127,7 +127,14 @@ function _sendDashboardPresence(closed) {
127
127
 
128
128
  window.addEventListener('pagehide', function() { _sendDashboardPresence(true); });
129
129
  window.addEventListener('beforeunload', function() { _sendDashboardPresence(true); });
130
- document.addEventListener('visibilitychange', function() { _sendDashboardPresence(false); });
130
+ // Only ping on becoming visible — hidden->presence beacons race the pagehide close
131
+ // beacon (both fire on tab close in quick succession via sendBeacon, ordering not
132
+ // guaranteed) and can resurrect a just-deleted entry with visibility:"hidden".
133
+ // Hidden tabs naturally expire via the 45s presence window; foreground returns
134
+ // re-fire visibilitychange so we still get a fresh heartbeat when the user comes back.
135
+ document.addEventListener('visibilitychange', function() {
136
+ if (document.visibilityState === 'visible') _sendDashboardPresence(false);
137
+ });
131
138
 
132
139
  function rerenderPrdFromCache() {
133
140
  if (!window._lastStatus || !window._lastStatus.prdProgress) return;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "runtime": "copilot",
3
3
  "models": null,
4
- "cachedAt": "2026-05-09T15:29:07.860Z"
4
+ "cachedAt": "2026-05-09T17:41:50.994Z"
5
5
  }
@@ -158,55 +158,32 @@ function injectAdoTokenEnvForRepoHost(env, opts) {
158
158
  return injectAdoTokenEnv(env, opts);
159
159
  }
160
160
 
161
- const PROCESS_EXIT_SENTINEL_FLUSH_TIMEOUT_MS = 2000;
162
-
163
161
  function formatProcessExitSentinel(exitCode, signal) {
164
162
  return `\n[process-exit] code=${exitCode}${signal ? ` signal=${signal}` : ''}\n`;
165
163
  }
166
164
 
167
- function _appendSentinelFallback(outputPath, sentinel) {
168
- if (!outputPath) return false;
169
- try {
170
- fs.appendFileSync(outputPath, sentinel);
171
- return true;
172
- } catch {
173
- return false;
174
- }
175
- }
176
-
177
- function _writeStdoutWithTimeout(stdout, sentinel, timeoutMs) {
178
- return new Promise((resolve) => {
179
- let settled = false;
180
- const finish = (flushed) => {
181
- if (settled) return;
182
- settled = true;
183
- clearTimeout(timer);
184
- resolve(flushed);
185
- };
186
- const timer = setTimeout(() => finish(false), Math.max(0, timeoutMs));
187
- try {
188
- if (!stdout || typeof stdout.write !== 'function') {
189
- finish(false);
190
- return;
191
- }
192
- stdout.write(sentinel, () => finish(true));
193
- } catch {
194
- finish(false);
195
- }
196
- });
197
- }
198
-
199
- async function writeProcessExitSentinel({
165
+ // The orphan reaper recovers an agent's exit code by scanning live-output.log for
166
+ // `[process-exit] code=N`. The previous design wrote the sentinel to stdout, hoping
167
+ // the engine's stdout consumer (engine.js) would copy it into the file — but when
168
+ // the engine was force-killed during a restart on Windows, the broken pipe
169
+ // silently swallowed the sentinel and the recovery never happened (see #2265 for
170
+ // the read-side recovery; this is the upstream fix). The orphan reaper only reads
171
+ // the file, so the simplest correct thing is to write the file directly. No
172
+ // stdout, no timeouts, no callbacks — one synchronous append.
173
+ function writeProcessExitSentinel({
200
174
  exitCode,
201
175
  signal = null,
202
- stdout = process.stdout,
203
176
  outputPath = process.env.MINIONS_LIVE_OUTPUT_PATH,
204
- timeoutMs = PROCESS_EXIT_SENTINEL_FLUSH_TIMEOUT_MS,
205
177
  } = {}) {
206
178
  const sentinel = formatProcessExitSentinel(exitCode, signal);
207
- const stdoutFlushed = await _writeStdoutWithTimeout(stdout, sentinel, timeoutMs);
208
- const outputPathWritten = stdoutFlushed ? false : _appendSentinelFallback(outputPath, sentinel);
209
- return { sentinel, stdoutFlushed, outputPathWritten };
179
+ let fileWritten = false;
180
+ if (outputPath) {
181
+ try {
182
+ fs.appendFileSync(outputPath, sentinel);
183
+ fileWritten = true;
184
+ } catch { /* file unavailable; orphan reaper falls back to runtime result event (#2265) */ }
185
+ }
186
+ return { sentinel, fileWritten };
210
187
  }
211
188
 
212
189
  function _appendOutputFallback(outputPath, chunk, prefix = '') {
@@ -432,19 +409,19 @@ function main() {
432
409
  }, MCP_STARTUP_TIMEOUT);
433
410
  proc.stdout.once('data', () => { gotFirstOutput = true; clearTimeout(startupTimer); });
434
411
 
435
- proc.on('close', async (code, signal) => {
412
+ proc.on('close', (code, signal) => {
436
413
  clearTimeout(startupTimer);
437
414
  const exitCode = normalizeRuntimeExit(code, signal);
438
- const sentinelResult = await writeProcessExitSentinel({ exitCode, signal });
415
+ const sentinelResult = writeProcessExitSentinel({ exitCode, signal });
439
416
  fs.appendFileSync(debugPath, `EXIT: code=${exitCode}${signal ? ` signal=${signal}` : ''}\nSTDERR: ${stderrBuf.slice(0, 500)}\n`);
440
- if (!sentinelResult.stdoutFlushed && sentinelResult.outputPathWritten) {
441
- fs.appendFileSync(debugPath, `EXIT SENTINEL FALLBACK: ${process.env.MINIONS_LIVE_OUTPUT_PATH}\n`);
417
+ if (!sentinelResult.fileWritten) {
418
+ fs.appendFileSync(debugPath, `EXIT SENTINEL: file write failed for ${process.env.MINIONS_LIVE_OUTPUT_PATH}\n`);
442
419
  }
443
420
  process.exit(exitCode);
444
421
  });
445
- proc.on('error', async (err) => {
422
+ proc.on('error', (err) => {
446
423
  fs.appendFileSync(debugPath, `ERROR: ${err.message}\n`);
447
- await writeProcessExitSentinel({ exitCode: 1 });
424
+ writeProcessExitSentinel({ exitCode: 1 });
448
425
  process.exit(1);
449
426
  });
450
427
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1817",
3
+ "version": "0.1.1819",
4
4
  "description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
5
5
  "bin": {
6
6
  "minions": "bin/minions.js"