open-claude-p 1.1.1 → 1.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [1.1.2] — 2026-05-19
11
+
12
+ Recovery-path fixes for the sentinel-missing case. When the end-of-reply
13
+ marker fails to land — usually because claude omitted it or the PTY
14
+ frames were truncated — the driver's text extraction was returning
15
+ either an empty string or, worse, the entire re-rendered transcript of
16
+ a `--resume` session. Two changes correct that.
17
+
18
+ ### Fixed
19
+
20
+ - **`extractAssistantText` no longer slices from the FIRST `⏺`** when
21
+ the sentinel is missing. On a `--resume` run the buffer carries old
22
+ history regions before the current response; anchoring on the first
23
+ `⏺` returned the oldest history turn plus everything after it,
24
+ silently leaking prior turns into `result.text`. The fallback now
25
+ uses `lastIndexOf('⏺')` so the slice always covers the current
26
+ turn's response. Fresh (non-resumed) sessions are unaffected because
27
+ the buffer only has one region marker, so first == last.
28
+
29
+ ### Added
30
+
31
+ - **Degraded-capture notice prefix.** When `completionReason` is
32
+ `'idle'` (sentinel never seen, idle-fallback completed) or
33
+ `'jsonl-recovered'` (a stall was rescued by reading the upstream
34
+ JSONL session log), `result.text` is now prefixed with:
35
+
36
+ ```
37
+ [ocp] Streaming capture not detected — showing last result from {source}.
38
+ ```
39
+
40
+ where `{source}` is either `local session log` (JSONL had the
41
+ response) or `terminal buffer (best effort)` (JSONL was unavailable
42
+ and we fell back to the PTY slice above). Callers and chat UIs can
43
+ now distinguish a normal capture from a post-hoc recovery without
44
+ inspecting `completionReason`. The default success path
45
+ (`reason='sentinel'`) is unchanged — no prefix is added.
46
+
47
+ ---
48
+
10
49
  ## [1.1.1] — 2026-05-19
11
50
 
12
51
  Post-1.1.0 fixes driven by Cosmica integration testing. Several of
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-claude-p",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "A PTY-backed compatibility shim for `claude -p` (Claude Code headless/print mode). Drives the interactive `claude` CLI via node-pty and exposes the same option surface and stream-json contract. Ships as both a library and an `ocp` CLI binary.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/index.js CHANGED
@@ -775,6 +775,28 @@ class Driver {
775
775
  );
776
776
  }
777
777
 
778
+ // Degraded-capture notice. When the per-turn sentinel never landed
779
+ // (`reason='idle'`) or a stalled completion was rescued via JSONL
780
+ // (`reason='jsonl-recovered'`), the streamed PTY frames did NOT
781
+ // produce a clean end-of-reply boundary. The text we are returning
782
+ // is a post-hoc recovery — usually from the upstream JSONL session
783
+ // log, or as a best-effort tail of the PTY buffer when JSONL was
784
+ // unavailable. Prepend a one-line notice so the caller (and any
785
+ // chat UI rendering it) can tell this apart from a normal capture.
786
+ // The notice is intentionally a literal English prefix and only
787
+ // appears on the degraded path — the default success path
788
+ // (`reason='sentinel'`) is unchanged.
789
+ const captureFailed =
790
+ effectiveCompletion === 'idle' || effectiveCompletion === 'jsonl-recovered';
791
+ if (captureFailed && text) {
792
+ const source = jsonlExtraction?.text
793
+ ? 'local session log'
794
+ : 'terminal buffer (best effort)';
795
+ text =
796
+ `[ocp] Streaming capture not detected — showing last result from ${source}.\n\n` +
797
+ text;
798
+ }
799
+
778
800
  // For stall-style failures, capture the tail of the stripped PTY
779
801
  // buffer so the caller can see exactly what claude was rendering
780
802
  // when we gave up — that is usually the dialog or error that the
@@ -1144,9 +1166,12 @@ function extractAssistantText(stripped, nonce) {
1144
1166
  sentinelIdx = i;
1145
1167
  }
1146
1168
  if (sentinelIdx === -1) {
1147
- // Fall back to "everything after the first ⏺" — this preserves the
1148
- // legacy behavior when the model dropped the sentinel.
1149
- const ri = stripped.indexOf(marker);
1169
+ // Sentinel-missing fallback. On a resumed session the buffer carries
1170
+ // history regions before the current response, so anchoring on the
1171
+ // FIRST `⏺` would slice from the oldest history turn and return the
1172
+ // entire re-rendered transcript. Anchor on the LAST `⏺` instead —
1173
+ // that's the region marker for the current turn even after `--resume`.
1174
+ const ri = stripped.lastIndexOf(marker);
1150
1175
  return ri === -1 ? '' : stripped.slice(ri + marker.length).trim();
1151
1176
  }
1152
1177