@sweny-ai/core 0.1.135 → 0.1.136

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.
@@ -382,6 +382,9 @@ export class ClaudeCodeHarness {
382
382
  // emitted no usage (mocks, older SDKs), so `usage` stays absent rather
383
383
  // than shipping zeroes that read as a real (free) run.
384
384
  let usage;
385
+ // Fail closed: a stream that ends with no terminal `result` message
386
+ // (subprocess died, stream truncated) is not a success.
387
+ let sawResult = false;
385
388
  // Timeout / abort wiring (back-compat: only armed when requested).
386
389
  // A single AbortController drives both an optional caller signal and an
387
390
  // optional timeout timer. The SDK aborts the subprocess when this fires.
@@ -493,6 +496,7 @@ export class ClaudeCodeHarness {
493
496
  }
494
497
  else if (message.type === "result") {
495
498
  const resultMsg = message;
499
+ sawResult = true;
496
500
  // Capture token/cost accounting off the terminal result. Present on
497
501
  // both success and error subtypes; shape-only. Attached to every
498
502
  // return below (including early-termination and error paths).
@@ -564,6 +568,16 @@ export class ClaudeCodeHarness {
564
568
  abort?.clear();
565
569
  await interruptStream(stream);
566
570
  }
571
+ if (!sawResult) {
572
+ const msg = "agent stream ended without a result message";
573
+ this.logger.warn(`Claude Code query: ${msg}; failing closed (${toolCalls.length} tool calls captured).`);
574
+ return {
575
+ status: "failed",
576
+ data: { error: msg },
577
+ toolCalls,
578
+ ...(usage ? { usage } : {}),
579
+ };
580
+ }
567
581
  // CC-08: prefer the SDK's validated structured output when it gave us an
568
582
  // object. Fall back to the free-text JSON heuristic when it's absent
569
583
  // (no schema requested, mocked result, or an older SDK that didn't set it).
@@ -593,6 +607,7 @@ export class ClaudeCodeHarness {
593
607
  const effectiveModel = model ?? this.model;
594
608
  const abort = makeAbort(timeoutMs, signal);
595
609
  let failed = false;
610
+ let sawResult = false;
596
611
  let stream;
597
612
  try {
598
613
  stream = query({
@@ -621,6 +636,7 @@ export class ClaudeCodeHarness {
621
636
  for await (const message of stream) {
622
637
  if (message.type === "result") {
623
638
  const resultMsg = message;
639
+ sawResult = true;
624
640
  if (resultMsg.subtype === "success" && "result" in resultMsg) {
625
641
  response = resultMsg.result;
626
642
  }
@@ -661,6 +677,10 @@ export class ClaudeCodeHarness {
661
677
  abort?.clear();
662
678
  await interruptStream(stream);
663
679
  }
680
+ if (!sawResult) {
681
+ this.logger.warn(`claude.${purpose}: agent stream ended without a result message ${DASH} failing closed.`);
682
+ return null;
683
+ }
664
684
  return failed ? null : response;
665
685
  }
666
686
  /** Route evaluation. Delegates to core {@link coreEvaluate} over {@link complete}. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sweny-ai/core",
3
- "version": "0.1.135",
3
+ "version": "0.1.136",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sweny": "./dist/cli/main.js"