@quantiya/codevibe-claude-plugin 2.0.15 → 2.0.17

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.
@@ -104,7 +104,10 @@ if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
104
104
  # Take messages after the real user prompt, filter to unsent assistant text
105
105
  .[($startIdx + 1):] |
106
106
  .[] |
107
- select(.type == "assistant") |
107
+ # Claude Code's synthetic API-error record (isApiErrorMessage == true, model
108
+ # "<synthetic>") is NOT assistant text: the daemon's transcript backstop relays
109
+ # it as a NOTIFICATION (src/transcript-api-error.ts). Same exclusion as stop.sh.
110
+ select(.type == "assistant" and (.isApiErrorMessage != true)) |
108
111
  select(.uuid as $u | $sentList | any(. == $u) | not) |
109
112
  {
110
113
  uuid: .uuid,
package/hooks/stop.sh CHANGED
@@ -45,6 +45,9 @@ EVENTS_SENT=0
45
45
  # → walker submits → Claude responds with "Got it..." while transcript
46
46
  # write is still in flight).
47
47
  ASSISTANT_TEXT_SENT=0
48
+ # base64 texts of API-error records seen in this turn (space-separated tokens);
49
+ # the last_assistant_message fallback must never re-send one of them.
50
+ API_ERROR_TEXTS_B64=""
48
51
 
49
52
  # Track sent message UUIDs to avoid duplicates (shared with PermissionRequest hook)
50
53
  SENT_UUIDS_FILE="${CODEVIBE_TMPDIR}/codevibe-claude-sent-uuids-${SESSION_ID}.txt"
@@ -100,11 +103,23 @@ read -r -d '' JQ_FILTER <<'JQEOF' || true
100
103
  else
101
104
  # Parse sent UUIDs
102
105
  ($sent | split("\n") | map(select(. != ""))) as $sentList |
103
- # Take messages after the real user prompt
106
+ # Take messages after the real user prompt. A synthetic API-error record
107
+ # (isApiErrorMessage == true — Claude Code's own yellow "There's an issue
108
+ # with the selected model…" line, written with model "<synthetic>") is NOT an
109
+ # assistant response: the daemon's transcript backstop relays it as a
110
+ # NOTIFICATION (see src/transcript-api-error.ts), so it must never be sent
111
+ # here as ASSISTANT_RESPONSE (a Stop after an in-turn fallback retry would
112
+ # otherwise double-post it as a green assistant bubble).
104
113
  .[($startIdx + 1):] |
105
114
  .[] |
106
115
  select(.type == "assistant") |
107
116
  . as $msg |
117
+ if ($msg.isApiErrorMessage == true) then
118
+ # Excluded record class: report it (base64 text) so the fallback below can
119
+ # recognise the same text in last_assistant_message and skip it too.
120
+ ([$msg.message.content[]? | select(.type == "text") | .text // empty] | join("\n\n")) as $errText |
121
+ "\($msg.uuid)\tapi_error\t\($errText | @base64)"
122
+ else
108
123
  # Emit text content (base64-encoded to preserve newlines)
109
124
  (
110
125
  ($msg.uuid) as $uuid |
@@ -123,6 +138,7 @@ read -r -d '' JQ_FILTER <<'JQEOF' || true
123
138
  $msg.message.content[]? | select(.type == "tool_use") |
124
139
  "\($msg.uuid)\ttool_use\t\(. | tojson | @base64)"
125
140
  )
141
+ end
126
142
  end
127
143
  JQEOF
128
144
  JQ_STDERR=$(mktemp)
@@ -152,6 +168,14 @@ if [ -n "$TRANSCRIPT_EVENTS" ]; then
152
168
  continue
153
169
  fi
154
170
 
171
+ if [ "$MSG_TYPE" = "api_error" ]; then
172
+ # Claude Code's synthetic API-error record (isApiErrorMessage). The daemon's
173
+ # transcript backstop relays it as a NOTIFICATION; never an ASSISTANT_RESPONSE.
174
+ log "INFO" "Skipping API-error record UUID: $MSG_UUID (relayed by the daemon as NOTIFICATION)"
175
+ [ -n "$MSG_CONTENT" ] && API_ERROR_TEXTS_B64="$API_ERROR_TEXTS_B64 $MSG_CONTENT"
176
+ continue
177
+ fi
178
+
155
179
  if [ "$MSG_TYPE" = "text" ] && [ -n "$MSG_CONTENT" ]; then
156
180
  # Decode base64-encoded text content
157
181
  DECODED_CONTENT=$(echo "$MSG_CONTENT" | base64 -d 2>/dev/null || echo "$MSG_CONTENT")
@@ -281,6 +305,17 @@ fi
281
305
  # is still in flight) silently swallows the final response.
282
306
  if [ "$ASSISTANT_TEXT_SENT" -eq 0 ]; then
283
307
  LAST_ASSISTANT_MSG=$(echo "$INPUT" | jq -r '.last_assistant_message // empty')
308
+ # Never re-send an API-error record's text through the fallback either: if
309
+ # last_assistant_message equals a record the transcript scan excluded above,
310
+ # the daemon owns it (NOTIFICATION) and the fallback is suppressed.
311
+ for ERR_B64 in $API_ERROR_TEXTS_B64; do
312
+ ERR_TEXT=$(echo "$ERR_B64" | base64 -d 2>/dev/null || true)
313
+ if [ -n "$ERR_TEXT" ] && [ "$LAST_ASSISTANT_MSG" = "$ERR_TEXT" ]; then
314
+ log "INFO" "Fallback suppressed: last_assistant_message is the API-error record (relayed by the daemon as NOTIFICATION)"
315
+ LAST_ASSISTANT_MSG=""
316
+ break
317
+ fi
318
+ done
284
319
  if [ -n "$LAST_ASSISTANT_MSG" ] && [ "$LAST_ASSISTANT_MSG" != "null" ]; then
285
320
  log "INFO" "Assistant text missing from transcript scan (EVENTS_SENT=$EVENTS_SENT), using last_assistant_message fallback"
286
321
  FALLBACK_PAYLOAD=$(jq -n \
@@ -3,7 +3,7 @@ import { CreateEventInput, CreateSessionInput, UpdateSessionInput, UpdateEventSt
3
3
  import type { PostDecisionAction } from '../orchestration-shell/types';
4
4
  import type { InvocationUsageSnapshot } from '../reviewer/token-usage';
5
5
  import type { CreateTaskGroupInput, CreateTaskGroupResult, SubmitMergeGateVerdictInput, SubmitMergeGateVerdictResult, SubmitTrackVerificationOutcomeInput, SubmitTrackVerificationOutcomeResult, ClaimGroupDecisionInput, ClaimGroupDecisionResult } from '../local-executor/task-group-types';
6
- import type { ReviewerVerdict, ReviewerRole, AgentKind as ReviewerAgentKind } from '../reviewer/types';
6
+ import type { ReviewScopeContext, ReviewerVerdict, ReviewerRole, AgentKind as ReviewerAgentKind } from '../reviewer/types';
7
7
  import type { PlannerDecision } from '../planner/types';
8
8
  /**
9
9
  * Dispose a watcher/subscription WebSocket without crashing the process
@@ -171,6 +171,8 @@ export interface ReviewerPromptResult {
171
171
  role: ReviewerRole;
172
172
  /** Decrypted plaintext rendered prompt (UTF-8) → ReviewerSpec.prompt_template. */
173
173
  prompt: string;
174
+ /** Server-authored P24 scope; prior finding text is redacted because it is already in the encrypted prompt. */
175
+ reviewScope?: ReviewScopeContext | null;
174
176
  }
175
177
  /** One reviewer seat in a round's `reviewers[]` (decrypted). */
176
178
  export interface TaskReviewSummaryReviewer {
@@ -924,6 +926,8 @@ export declare class AppSyncClient {
924
926
  roundNumber: number;
925
927
  rawOutput: string;
926
928
  usage?: InvocationUsageSnapshot;
929
+ /** P24 explicit comprehensive-baseline reset for a revise round. */
930
+ reviewScopeReset?: boolean;
927
931
  }, sessionKeyBase64: string): Promise<{
928
932
  gateId: string;
929
933
  workflowState: string;