@testchimp/cli 0.1.52 → 0.1.53

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.
@@ -115,6 +115,8 @@ class AgentEventPoster {
115
115
  lastStreamPostAt = 0;
116
116
  /** When false, liveStream tokens are dropped; completed events still persist. */
117
117
  uiAttached = false;
118
+ ephemeralFailLogAt = 0;
119
+ ephemeralFailCount = 0;
118
120
  constructor(backend, apiKey, sessionId) {
119
121
  this.backend = backend;
120
122
  this.apiKey = apiKey;
@@ -163,6 +165,7 @@ class AgentEventPoster {
163
165
  eph.opencodeSessionId = opts.opencodeSessionId;
164
166
  try {
165
167
  const text = await postJson(this.backend, this.apiKey, "/api/chimphands/post_ephemeral_agent_event", eph);
168
+ this.ephemeralFailCount = 0;
166
169
  let delivered = false;
167
170
  try {
168
171
  const parsed = JSON.parse(text);
@@ -176,7 +179,7 @@ class AgentEventPoster {
176
179
  // Mid-turn liveStream must not fall through to durable — that would write
177
180
  // every token to PG. Turn-end reconcile persists the final transcript.
178
181
  if (opts?.liveStream) {
179
- console.error("ChimpHands ephemeral not delivered (replica miss?) — skipping durable for liveStream");
182
+ this.logEphemeralIssue("ephemeral not delivered (replica miss?) — skipping durable for liveStream");
180
183
  return;
181
184
  }
182
185
  // Completed/non-live: durable fallback for cross-replica UI.
@@ -185,7 +188,7 @@ class AgentEventPoster {
185
188
  catch (err) {
186
189
  const detail = err instanceof Error ? err.message : String(err);
187
190
  if (opts?.liveStream) {
188
- console.error(`ChimpHands ephemeral post failed — skipping durable for liveStream: ${detail}`);
191
+ this.logEphemeralIssue(`ephemeral post failed — skipping durable for liveStream: ${detail}`);
189
192
  return;
190
193
  }
191
194
  console.error(`ChimpHands ephemeral post failed — durable fallback: ${detail}`);
@@ -195,6 +198,16 @@ class AgentEventPoster {
195
198
  });
196
199
  return this.chain;
197
200
  }
201
+ /** Avoid flooding GHA logs when ephemeral 500s every ~150ms. */
202
+ logEphemeralIssue(message) {
203
+ this.ephemeralFailCount += 1;
204
+ const now = Date.now();
205
+ if (this.ephemeralFailCount <= 2 || now - this.ephemeralFailLogAt >= 10_000) {
206
+ this.ephemeralFailLogAt = now;
207
+ const suffix = this.ephemeralFailCount > 2 ? ` (x${this.ephemeralFailCount} since last log)` : "";
208
+ console.error(`ChimpHands ${message}${suffix}`);
209
+ }
210
+ }
198
211
  fireAndForget(role, content, opts) {
199
212
  void this.enqueue(role, content, opts).catch((err) => {
200
213
  const detail = err instanceof Error ? err.message : String(err);
@@ -874,20 +887,34 @@ function killListenersOnPort(port) {
874
887
  async function waitForOpencodeHttp(attachUrl, timeoutMs) {
875
888
  const base = attachUrl.replace(/\/$/, "");
876
889
  const deadline = Date.now() + timeoutMs;
890
+ const perTryMs = 2_000;
891
+ let attempt = 0;
892
+ let lastErr = "";
877
893
  while (Date.now() < deadline) {
894
+ attempt += 1;
878
895
  for (const path of ["/global/health", "/"]) {
879
896
  try {
880
- const res = await fetch(`${base}${path}`);
881
- if (res.ok || res.status === 401 || res.status === 404)
897
+ const res = await fetch(`${base}${path}`, {
898
+ signal: AbortSignal.timeout(perTryMs),
899
+ });
900
+ if (res.ok || res.status === 401 || res.status === 404) {
901
+ console.error(`ChimpHands OpenCode HTTP ready at ${attachUrl}${path} (http ${res.status}, attempt ${attempt})`);
882
902
  return;
903
+ }
904
+ lastErr = `HTTP ${res.status}`;
883
905
  }
884
- catch {
885
- /* retry */
906
+ catch (err) {
907
+ lastErr = err instanceof Error ? err.message : String(err);
886
908
  }
887
909
  }
910
+ if (attempt === 1 || attempt % 5 === 0) {
911
+ const left = Math.max(0, deadline - Date.now());
912
+ console.error(`ChimpHands waiting for OpenCode HTTP at ${attachUrl} (attempt ${attempt}, ${Math.ceil(left / 1000)}s left): ${lastErr || "not ready"}`);
913
+ }
888
914
  await sleep(400);
889
915
  }
890
- throw new Error(`OpenCode server not ready at ${attachUrl} within ${timeoutMs}ms`);
916
+ throw new Error(`OpenCode server not ready at ${attachUrl} within ${timeoutMs}ms` +
917
+ (lastErr ? ` (last: ${lastErr})` : ""));
891
918
  }
892
919
  /**
893
920
  * Restart local `opencode serve` after writing opencode.json so the server loads
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testchimp/cli",
3
- "version": "0.1.52",
3
+ "version": "0.1.53",
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",