@cloudgrid-io/mcp 0.20.19 → 0.20.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudgrid-io/mcp",
3
- "version": "0.20.19",
3
+ "version": "0.20.20",
4
4
  "description": "Use CloudGrid via MCP to brainstorm, build, deploy, and improve apps, games, websites, dashboards, and tools and get a live URL - templates, recipes, managed databases and AI, instant single-page publish, and full-app deploys, for developers and non-technical users. Three editions: local stdio (full toolset), hosted web (light, CLI-free), and a public docs-search server, over MCP.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,7 +22,8 @@ const TEXT_SECRET_PATTERNS = [
22
22
  /\bAKIA[0-9A-Z]{16}\b/g, // AWS access key id
23
23
  /\bAIza[0-9A-Za-z_\-]{30,}\b/g, // Google API key
24
24
  /\bsk_(?:live|test)_[0-9A-Za-z]{16,}\b/g, // Stripe secret keys
25
- /\bsk-[A-Za-z0-9]{16,}/g, // sk- API keys
25
+ /\bsk-ant-[A-Za-z0-9_-]{20,}/g, // Anthropic API keys (sk-ant-…, hyphenated)
26
+ /\bsk-[A-Za-z0-9]{16,}/g, // other sk- API keys
26
27
  /\b[0-9a-fA-F]{32,}\b/g, // long hex runs
27
28
  ];
28
29
  export function scrubText(text) {
@@ -98,6 +99,7 @@ export function renderLogText(p) {
98
99
  const dur = c.duration_ms != null ? ` (${(c.duration_ms / 1000).toFixed(1)}s)` : "";
99
100
  lines.push(`[${c.at}] ${c.name}${args} ${c.outcome}${dur}`);
100
101
  if (c.key) lines.push(` → ${c.key}`);
102
+ if (c.error_reason) lines.push(` ✗ ${c.error_reason}`);
101
103
  }
102
104
  lines.push(RULE);
103
105
  lines.push(
@@ -171,12 +173,21 @@ export class SessionLogger {
171
173
  await this.resolveHeader();
172
174
  const outcome = result?.isError ? "error" : "ok";
173
175
  const args = scrubArgs(input);
176
+ // On an error, capture WHY (scrubbed): the throw path passes errorMessage;
177
+ // a returned fail() puts the message in content[0].text. Without this the
178
+ // log only said "error" and every failure needed a blind repro.
179
+ let errorReason = null;
180
+ if (outcome === "error") {
181
+ const raw = result?.errorMessage || result?.content?.[0]?.text || null;
182
+ if (raw) errorReason = scrubText(String(raw)).slice(0, 300);
183
+ }
174
184
  this.calls.push({
175
185
  at: this._clock(this.now()),
176
186
  name,
177
187
  args,
178
188
  outcome,
179
189
  key: this._keyResult(name, result),
190
+ error_reason: errorReason,
180
191
  duration_ms: durationMs,
181
192
  });
182
193
  // Only a deploy failure (grid_deploy) is the QA "failure" trigger. Other
@@ -50,9 +50,11 @@ export function registerTools(server, ctx) {
50
50
  return result;
51
51
  } catch (err) {
52
52
  // A thrown handler must record as an ERROR — the old finally-based capture
53
- // saw result=undefined and mis-recorded it as "ok". Synthesize an error
54
- // result, then rethrow so the tool contract is unchanged.
55
- try { ctx.logger?.recordCall(name, input, { isError: true }, Date.now() - started); } catch { /* never */ }
53
+ // saw result=undefined and mis-recorded it as "ok". Carry the error
54
+ // message so the QA log says WHY, not just "error" (diagnosability: a
55
+ // Songsmith hosted deploy logged a bare "error" and cost four blind
56
+ // reproductions). Synthesize an error result, then rethrow unchanged.
57
+ try { ctx.logger?.recordCall(name, input, { isError: true, errorMessage: String(err?.message || err) }, Date.now() - started); } catch { /* never */ }
56
58
  throw err;
57
59
  }
58
60
  };