@testchimp/cli 0.1.56 → 0.1.57

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.
@@ -753,6 +753,35 @@ function isMissingOpencodeSessionError(message) {
753
753
  m.includes("unknown session") ||
754
754
  m.includes("invalid session"));
755
755
  }
756
+ /** Strip one layer of wrapping quotes models sometimes add when echoing. */
757
+ function stripOuterQuotes(text) {
758
+ const a = String(text || "").trim();
759
+ if ((a.startsWith('"') && a.endsWith('"')) ||
760
+ (a.startsWith("'") && a.endsWith("'"))) {
761
+ return a.slice(1, -1).trim();
762
+ }
763
+ return a;
764
+ }
765
+ /**
766
+ * True when assistant text is an echo of a prompt we just sent to OpenCode
767
+ * (raw user text and/or host-wrapped effectivePrompt) — exact or streaming prefix.
768
+ */
769
+ function isAssistantEchoOfSentPrompt(assistant, ...sentPrompts) {
770
+ const a = stripOuterQuotes(assistant);
771
+ if (!a)
772
+ return false;
773
+ for (const raw of sentPrompts) {
774
+ const p = String(raw || "").trim();
775
+ if (!p)
776
+ continue;
777
+ if (a === p)
778
+ return true;
779
+ // Streaming echo of the (usually long) wrapped prompt: only when clearly a prefix.
780
+ if (p.length >= 64 && a.length >= 24 && p.startsWith(a))
781
+ return true;
782
+ }
783
+ return false;
784
+ }
756
785
  function wrapPromptWithContext(conversationSummary, userPrompt, isNewOpencodeSession, workingBranch, pullRequestUrl) {
757
786
  const parts = [];
758
787
  if (workingBranch?.trim()) {
@@ -1450,19 +1479,13 @@ export async function runChimphands(opts) {
1450
1479
  }
1451
1480
  poster.fireAndForget(role, content, bodyOpts);
1452
1481
  };
1453
- /** Drop assistant bubbles that are just the current user prompt echoed (often quoted). */
1454
- const postEventForTurn = (userPrompt, role, content, opts) => {
1455
- if (role === ROLE_ASSISTANT) {
1456
- const a = String(content || "").trim();
1457
- const u = normalizeUserMessage(userPrompt);
1458
- if (a && u) {
1459
- const unquoted = (a.startsWith('"') && a.endsWith('"')) || (a.startsWith("'") && a.endsWith("'"))
1460
- ? a.slice(1, -1).trim()
1461
- : a;
1462
- if (a === u || unquoted === u) {
1463
- return;
1464
- }
1465
- }
1482
+ /**
1483
+ * Drop ASSISTANT bubbles that echo the prompt we just sent — either the raw
1484
+ * user text or the host-wrapped effectivePrompt (exact string OpenCode got).
1485
+ */
1486
+ const postEventForTurn = (userPrompt, wrappedPrompt, role, content, opts) => {
1487
+ if (role === ROLE_ASSISTANT && isAssistantEchoOfSentPrompt(content, userPrompt, wrappedPrompt)) {
1488
+ return;
1466
1489
  }
1467
1490
  postEvent(role, content, opts);
1468
1491
  };
@@ -1564,7 +1587,7 @@ export async function runChimphands(opts) {
1564
1587
  let useOpencodeSessionId = opencodeSessionId;
1565
1588
  let isNewOpencodeSession = !useOpencodeSessionId;
1566
1589
  let effectivePrompt = wrapPromptWithContext(conversationSummary, prompt, isNewOpencodeSession, workingBranch, pullRequestUrl);
1567
- const turnPostEvent = (role, content, opts) => postEventForTurn(prompt, role, content, opts);
1590
+ const turnPostEvent = (role, content, opts) => postEventForTurn(prompt, effectivePrompt, role, content, opts);
1568
1591
  // Visible in chat (not filtered as routine). OpenCode may not emit text until a
1569
1592
  // part completes — without this the UI looks empty while the turn is running.
1570
1593
  postEvent(ROLE_STATUS, "Agent is working…", { status: STATUS_RUNNING });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testchimp/cli",
3
- "version": "0.1.56",
3
+ "version": "0.1.57",
4
4
  "description": "TestChimp CLI and MCP server — coverage, plans, EaaS, TrueCoverage, API operations (calls /api/mcp/*)",
5
5
  "type": "module",
6
6
  "main": "dist/bin/testchimp.js",