@link-assistant/hive-mind 1.22.2 → 1.22.4
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 +20 -0
- package/package.json +1 -1
- package/src/agent.lib.mjs +37 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @link-assistant/hive-mind
|
|
2
2
|
|
|
3
|
+
## 1.22.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2204f18: Fix workflow cancellation blocking by replacing always() with !cancelled() in Docker jobs (Issue #1278)
|
|
8
|
+
- Replace `always()` with `!cancelled()` in all Docker publish and Helm release job conditions
|
|
9
|
+
- Allow concurrency cancellation to properly interrupt Docker builds when new commits are pushed
|
|
10
|
+
- Reduce Docker job timeout from 60 to 30 minutes to minimize blocking time
|
|
11
|
+
- Fix issue where PR merges to main branch did not trigger releases due to stuck workflow runs
|
|
12
|
+
|
|
13
|
+
## 1.22.3
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 34a6937: Fix false positive error detection when agent recovers from transient errors (Issue #1276)
|
|
18
|
+
- Trust exit code 0 as authoritative indicator of success even if errors occurred during execution
|
|
19
|
+
- Clear streaming error detection when agent completes successfully (emits session.idle or "exiting loop")
|
|
20
|
+
- Fix message extraction to prefer "error" field over "message" field for agent error events
|
|
21
|
+
- Add tests for agent recovery scenarios and false positive prevention
|
|
22
|
+
|
|
3
23
|
## 1.22.2
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/package.json
CHANGED
package/src/agent.lib.mjs
CHANGED
|
@@ -559,6 +559,9 @@ export const executeAgentCommand = async params => {
|
|
|
559
559
|
// Post-hoc detection on fullOutput can miss errors if NDJSON lines get concatenated without newlines
|
|
560
560
|
let streamingErrorDetected = false;
|
|
561
561
|
let streamingErrorMessage = null;
|
|
562
|
+
// Issue #1276: Track successful completion events to clear error flags
|
|
563
|
+
// When agent emits session.idle or disposal events, it means it recovered and completed successfully
|
|
564
|
+
let agentCompletedSuccessfully = false;
|
|
562
565
|
// Issue #1250: Accumulate token usage during streaming instead of parsing fullOutput later
|
|
563
566
|
// This fixes the issue where NDJSON lines get concatenated without newlines, breaking JSON.parse
|
|
564
567
|
const streamingTokenUsage = {
|
|
@@ -641,6 +644,12 @@ export const executeAgentCommand = async params => {
|
|
|
641
644
|
// Explicit result message (like Claude outputs)
|
|
642
645
|
lastTextContent = data.result;
|
|
643
646
|
}
|
|
647
|
+
// Issue #1276: Detect successful completion events
|
|
648
|
+
// When agent emits session.idle or log with "exiting loop" message, it completed successfully
|
|
649
|
+
// This means any previous error events were recovered from (e.g., timeout then retry)
|
|
650
|
+
if (data.type === 'session.idle' || (data.type === 'log' && data.message === 'exiting loop')) {
|
|
651
|
+
agentCompletedSuccessfully = true;
|
|
652
|
+
}
|
|
644
653
|
} catch {
|
|
645
654
|
// Not JSON - log as plain text
|
|
646
655
|
await log(line);
|
|
@@ -698,6 +707,11 @@ export const executeAgentCommand = async params => {
|
|
|
698
707
|
} else if (stderrData.type === 'result' && stderrData.result) {
|
|
699
708
|
lastTextContent = stderrData.result;
|
|
700
709
|
}
|
|
710
|
+
// Issue #1276: Detect successful completion events (stderr)
|
|
711
|
+
// When agent emits session.idle or log with "exiting loop" message, it completed successfully
|
|
712
|
+
if (stderrData.type === 'session.idle' || (stderrData.type === 'log' && stderrData.message === 'exiting loop')) {
|
|
713
|
+
agentCompletedSuccessfully = true;
|
|
714
|
+
}
|
|
701
715
|
} catch {
|
|
702
716
|
// Not JSON - log as plain text
|
|
703
717
|
await log(stderrLine);
|
|
@@ -745,6 +759,19 @@ export const executeAgentCommand = async params => {
|
|
|
745
759
|
// Only check for JSON error messages, not pattern matching in output
|
|
746
760
|
const outputError = detectAgentErrors(fullOutput);
|
|
747
761
|
|
|
762
|
+
// Issue #1276: Clear streaming error detection if agent completed successfully
|
|
763
|
+
// When an error occurs during execution (e.g., timeout) but the agent recovers and completes,
|
|
764
|
+
// we should NOT treat it as a failure. The exit code is the authoritative success indicator.
|
|
765
|
+
// Check for: exit code 0 AND (completion event detected OR no streaming error)
|
|
766
|
+
if (exitCode === 0 && (agentCompletedSuccessfully || !streamingErrorDetected)) {
|
|
767
|
+
// Agent exited successfully - clear any streaming errors that were recovered from
|
|
768
|
+
if (streamingErrorDetected && agentCompletedSuccessfully) {
|
|
769
|
+
await log(`ℹ️ Agent recovered from earlier error and completed successfully`, { verbose: true });
|
|
770
|
+
}
|
|
771
|
+
streamingErrorDetected = false;
|
|
772
|
+
streamingErrorMessage = null;
|
|
773
|
+
}
|
|
774
|
+
|
|
748
775
|
// Issue #1201: Use streaming detection as primary, post-hoc as fallback
|
|
749
776
|
// Streaming detection is more reliable because it parses each JSON line as it arrives,
|
|
750
777
|
// avoiding issues where NDJSON lines get concatenated without newline delimiters in fullOutput
|
|
@@ -770,9 +797,16 @@ export const executeAgentCommand = async params => {
|
|
|
770
797
|
if (fullOutput.includes(pattern)) {
|
|
771
798
|
outputError.detected = true;
|
|
772
799
|
outputError.type = type;
|
|
773
|
-
// Try to extract the error message from the output
|
|
774
|
-
|
|
775
|
-
|
|
800
|
+
// Issue #1276: Try to extract the error message from the output
|
|
801
|
+
// First try "error" field (agent error format), then "message" field (generic format)
|
|
802
|
+
// Find the error closest to the "type": "error" pattern for more accurate extraction
|
|
803
|
+
const patternIndex = fullOutput.indexOf(pattern);
|
|
804
|
+
const relevantOutput = patternIndex >= 0 ? fullOutput.substring(patternIndex) : fullOutput;
|
|
805
|
+
// Look for "error" or "message" field near the error type pattern
|
|
806
|
+
const errorFieldMatch = relevantOutput.match(/"error":\s*"([^"]+)"/);
|
|
807
|
+
const messageFieldMatch = relevantOutput.match(/"message":\s*"([^"]+)"/);
|
|
808
|
+
// Prefer "error" field over "message" for agent error events
|
|
809
|
+
outputError.match = errorFieldMatch ? errorFieldMatch[1] : messageFieldMatch ? messageFieldMatch[1] : `Error event detected in output (fallback pattern match for ${pattern})`;
|
|
776
810
|
await log(`⚠️ Error event detected via fallback pattern match: ${outputError.match}`, { level: 'warning' });
|
|
777
811
|
break;
|
|
778
812
|
}
|