@rubytech/create-realagent 1.0.617 → 1.0.618

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.
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Real Agent</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/admin-Df1liz4Y.js"></script>
8
+ <script type="module" crossorigin src="/assets/admin-D7LRdkYB.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-Be6NvmcD.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-rov5CBGT.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/useVoiceRecorder-OB_Gtr0e.js">
@@ -6211,14 +6211,22 @@ function purgeOldLogs(logDir, prefix) {
6211
6211
  }
6212
6212
  }
6213
6213
  function teeProcStderrToStreamLog(proc, streamLog) {
6214
+ const pid = proc.pid;
6214
6215
  if (!proc.stderr) {
6215
- streamLog.write(`[${isoTs()}] [subproc-stderr-skip] reason=no-stderr
6216
+ streamLog.write(`[${isoTs()}] [subproc-stderr-skip] reason=no-stderr pid=${pid}
6216
6217
  `);
6217
6218
  return;
6218
6219
  }
6220
+ if (!streamLog.destroyed && !streamLog.writableEnded) {
6221
+ streamLog.write(`[${isoTs()}] [subproc-stderr-tee-attached] pid=${pid}
6222
+ `);
6223
+ }
6219
6224
  const utf8 = new StringDecoder("utf8");
6220
6225
  let buffer = "";
6226
+ let bytesSeen = 0;
6227
+ let linesEmitted = 0;
6221
6228
  proc.stderr.on("data", (chunk) => {
6229
+ bytesSeen += typeof chunk === "string" ? Buffer.byteLength(chunk, "utf8") : chunk.length;
6222
6230
  const text = typeof chunk === "string" ? chunk : utf8.write(chunk);
6223
6231
  buffer += text;
6224
6232
  let idx;
@@ -6229,12 +6237,18 @@ function teeProcStderrToStreamLog(proc, streamLog) {
6229
6237
  if (streamLog.destroyed || streamLog.writableEnded) continue;
6230
6238
  streamLog.write(`[${isoTs()}] [subproc-stderr] ${line}
6231
6239
  `);
6240
+ linesEmitted++;
6232
6241
  }
6233
6242
  });
6234
6243
  proc.stderr.on("end", () => {
6235
6244
  const tail = (buffer + utf8.end()).trim();
6236
6245
  if (tail.length > 0 && !streamLog.destroyed && !streamLog.writableEnded) {
6237
6246
  streamLog.write(`[${isoTs()}] [subproc-stderr] ${tail}
6247
+ `);
6248
+ linesEmitted++;
6249
+ }
6250
+ if (!streamLog.destroyed && !streamLog.writableEnded) {
6251
+ streamLog.write(`[${isoTs()}] [subproc-stderr-tee-detached] pid=${pid} bytes=${bytesSeen} lines=${linesEmitted}
6238
6252
  `);
6239
6253
  }
6240
6254
  buffer = "";
@@ -8284,10 +8298,11 @@ async function* runCompactionTurn(accountDir, accountId, systemPrompt, resumeSes
8284
8298
  env: {
8285
8299
  ...process.env,
8286
8300
  PLATFORM_ROOT: PLATFORM_ROOT4,
8287
- ACCOUNT_DIR: accountDir,
8288
- // Task 532: network traces on the compaction subprocess too its tool
8289
- // calls are part of the same conversation's record.
8290
- NODE_DEBUG: "http,http2,net,tls,undici,dns"
8301
+ ACCOUNT_DIR: accountDir
8302
+ // Task 535: NODE_DEBUG removed. The Claude Code CLI is a bundled Bun
8303
+ // binary and Bun ignores Node's NODE_DEBUG flag, so setting it here was
8304
+ // a no-op that misled future readers. The [subproc-debug-unavailable]
8305
+ // line below records the source-of-silence explicitly.
8291
8306
  }
8292
8307
  });
8293
8308
  const stderrLog = agentLogStream("claude-agent-compaction-stderr", accountDir, conversationId);
@@ -8298,6 +8313,8 @@ async function* runCompactionTurn(accountDir, accountId, systemPrompt, resumeSes
8298
8313
  streamLog.on("error", () => {
8299
8314
  });
8300
8315
  teeProcStderrToStreamLog(proc, streamLog);
8316
+ streamLog.write(`[${isoTs()}] [subproc-debug-unavailable] reason=bundled-bun-binary-ignores-node-debug pid=${proc.pid} cli=claude
8317
+ `);
8301
8318
  streamLog.write(`[${isoTs()}] [compaction-start] resumeSessionId=${resumeSessionId}
8302
8319
  `);
8303
8320
  proc.on("error", (err) => {
@@ -9171,11 +9188,11 @@ async function* invokeAdminAgent(message, systemPrompt, accountDir, accountId, a
9171
9188
  env: {
9172
9189
  ...process.env,
9173
9190
  PLATFORM_ROOT: PLATFORM_ROOT4,
9174
- ACCOUNT_DIR: accountDir,
9175
- // Task 532: tee subprocess network activity into the per-conversation
9176
- // stream log via the existing stderr pipe. Closes the Claude Code
9177
- // "what was the tool actually doing?" black box during tool waits.
9178
- NODE_DEBUG: "http,http2,net,tls,undici,dns"
9191
+ ACCOUNT_DIR: accountDir
9192
+ // Task 535: NODE_DEBUG removed. The Claude Code CLI is a bundled Bun
9193
+ // binary and Bun ignores Node's NODE_DEBUG flag, so setting it here was
9194
+ // a no-op that misled future readers. The [subproc-debug-unavailable]
9195
+ // line below records the source-of-silence explicitly.
9179
9196
  }
9180
9197
  });
9181
9198
  const stderrLog = agentLogStream("claude-agent-stderr", accountDir, spawnConvId);
@@ -9186,6 +9203,8 @@ async function* invokeAdminAgent(message, systemPrompt, accountDir, accountId, a
9186
9203
  streamLog.on("error", () => {
9187
9204
  });
9188
9205
  teeProcStderrToStreamLog(proc, streamLog);
9206
+ streamLog.write(`[${isoTs()}] [subproc-debug-unavailable] reason=bundled-bun-binary-ignores-node-debug pid=${proc.pid} cli=claude
9207
+ `);
9189
9208
  if (sessionKey) {
9190
9209
  const prev = activeProcesses.get(sessionKey);
9191
9210
  if (prev) {
@@ -9513,10 +9532,11 @@ async function* invokeManagedAdminAgent(message, systemPrompt, accountDir, accou
9513
9532
  env: {
9514
9533
  ...process.env,
9515
9534
  PLATFORM_ROOT: PLATFORM_ROOT4,
9516
- ACCOUNT_DIR: accountDir,
9517
- // Task 532: tee subprocess network traces into the per-conversation
9518
- // stream log via the stderr pipe + dual-consume listener.
9519
- NODE_DEBUG: "http,http2,net,tls,undici,dns"
9535
+ ACCOUNT_DIR: accountDir
9536
+ // Task 535: NODE_DEBUG removed. The Claude Code CLI is a bundled Bun
9537
+ // binary and Bun ignores Node's NODE_DEBUG flag, so setting it here was
9538
+ // a no-op that misled future readers. The [subproc-debug-unavailable]
9539
+ // line below records the source-of-silence explicitly.
9520
9540
  }
9521
9541
  });
9522
9542
  const stderrLog = agentLogStream("claude-agent-stderr", accountDir, managedConvId);
@@ -9524,6 +9544,8 @@ async function* invokeManagedAdminAgent(message, systemPrompt, accountDir, accou
9524
9544
  });
9525
9545
  proc.stderr?.pipe(stderrLog);
9526
9546
  teeProcStderrToStreamLog(proc, streamLog);
9547
+ streamLog.write(`[${isoTs()}] [subproc-debug-unavailable] reason=bundled-bun-binary-ignores-node-debug pid=${proc.pid} cli=claude
9548
+ `);
9527
9549
  if (sessionKey) {
9528
9550
  const prev = activeProcesses.get(sessionKey);
9529
9551
  if (prev) {
@@ -10480,6 +10502,26 @@ function defaultRules() {
10480
10502
  scope: "session",
10481
10503
  suggestedAction: "A tool call has been pending for 30 seconds without a result. Read the adjacent [tool-wait-diag] and [tool-wait-proc] lines in the conversation's stream log to determine whether the network remained healthy, the subprocess held active sockets, and the HTTP request reached the wire. If diag shows a healthy network but the subprocess has no [subproc-stderr] UNDICI/HTTP activity during the wait window, the tool's internal pipeline is stalled \u2014 do not retry the same request against the same target without a change in approach."
10482
10504
  },
10505
+ {
10506
+ // Task 536: detect agents ignoring the WEBFETCH_CANNOT_READ_JS_SPA
10507
+ // structured failure. A single SPA short-circuit per conversation is
10508
+ // expected — the hook is doing its job. Two or more in the same
10509
+ // conversation within 5 minutes means either (a) the agent retried
10510
+ // WebFetch on the same SPA URL despite the directive, or (b) the
10511
+ // owner is asking about multiple SPA URLs in one session and the
10512
+ // pattern needs surfacing as a recurring class. Both signal that the
10513
+ // IDENTITY.md "Tool Failure Discipline" guidance is not landing in the
10514
+ // prompt — revise the copy rather than add mechanical enforcement.
10515
+ id: "webfetch-spa-short-circuit-recurring",
10516
+ name: "WebFetch JS-SPA short-circuit fired repeatedly in conversation",
10517
+ type: "repeated-error",
10518
+ logSource: "system",
10519
+ pattern: "WEBFETCH_CANNOT_READ_JS_SPA",
10520
+ thresholdCount: 2,
10521
+ thresholdWindowMinutes: 5,
10522
+ scope: "session",
10523
+ suggestedAction: "The WebFetch SPA preflight has fired more than once in this conversation. Either the agent is ignoring the loud-failure directive (retrying WebFetch after seeing WEBFETCH_CANNOT_READ_JS_SPA), or multiple SPA URLs are being asked about. Read the conversation's stream log for the [tool-use] / [tool-result] sequence around each occurrence \u2014 if the agent dispatched WebFetch on the same URL or substituted Playwright silently, revisit the IDENTITY.md `Tool Failure Discipline` paragraph that names structured-error handling."
10524
+ },
10483
10525
  {
10484
10526
  // Task 533: surface every Cloudflare-plugin refusal. The plugin emits
10485
10527
  // exactly one [cloudflare:refuse] line per refusal with a structured
@@ -31172,18 +31214,23 @@ async function GET9(request) {
31172
31214
  const accountLogDir2 = account ? resolve19(account.accountDir, "logs") : null;
31173
31215
  if (fileParam) {
31174
31216
  const safe = basename5(fileParam);
31217
+ const searched = [];
31175
31218
  for (const dir of [accountLogDir2, LOG_DIR]) {
31176
31219
  if (!dir) continue;
31177
31220
  const filePath = resolve19(dir, safe);
31221
+ searched.push(filePath);
31178
31222
  try {
31179
31223
  const content = readFileSync20(filePath, "utf-8");
31180
31224
  const headers = { "Content-Type": "text/plain; charset=utf-8" };
31181
31225
  if (download) headers["Content-Disposition"] = `attachment; filename="${safe}"`;
31182
31226
  return new Response(content, { headers });
31183
- } catch {
31227
+ } catch (err) {
31228
+ const reason = err instanceof Error ? err.message : String(err);
31229
+ console.debug(`[admin/logs] miss dir=${dir} name=${safe} reason=${reason}`);
31184
31230
  }
31185
31231
  }
31186
- return Response.json({ error: `File not found: ${safe}` }, { status: 404 });
31232
+ console.warn(`[admin/logs] not-found name=${safe} searched=[${searched.join(",")}]`);
31233
+ return Response.json({ error: `File not found: ${safe}`, code: "NOT_FOUND" }, { status: 404 });
31187
31234
  }
31188
31235
  if (typeParam) {
31189
31236
  const prefixMap = {
@@ -31195,24 +31242,37 @@ async function GET9(request) {
31195
31242
  };
31196
31243
  const prefix = prefixMap[typeParam];
31197
31244
  if (!prefix) {
31198
- return Response.json({ error: `Unknown type: ${typeParam}. Valid: stream, error, session, sse, public` }, { status: 400 });
31245
+ console.warn(`[admin/logs] rejected reason=unknown-type type=${typeParam}`);
31246
+ return Response.json(
31247
+ { error: `Unknown type: ${typeParam}. Valid: stream, error, session, sse, public`, code: "UNKNOWN_TYPE" },
31248
+ { status: 400 }
31249
+ );
31199
31250
  }
31200
31251
  if (!conversationIdParam) {
31201
- return Response.json({ error: `type=${typeParam} requires conversationId (per-conversation log files, no daily fallback)` }, { status: 400 });
31252
+ console.warn(`[admin/logs] rejected type=${typeParam} reason=no-conversationId`);
31253
+ return Response.json(
31254
+ { error: `type=${typeParam} requires conversationId (per-conversation log files, no daily fallback)`, code: "CONVERSATION_ID_REQUIRED" },
31255
+ { status: 400 }
31256
+ );
31202
31257
  }
31203
31258
  const fileName = `${prefix}-${conversationIdParam}.log`;
31259
+ const searched = [];
31204
31260
  for (const dir of [accountLogDir2, LOG_DIR]) {
31205
31261
  if (!dir) continue;
31206
31262
  const filePath = resolve19(dir, fileName);
31263
+ searched.push(filePath);
31207
31264
  try {
31208
31265
  const content = readFileSync20(filePath, "utf-8");
31209
31266
  const headers = { "Content-Type": "text/plain; charset=utf-8" };
31210
31267
  if (download) headers["Content-Disposition"] = `attachment; filename="${fileName}"`;
31211
31268
  return new Response(content, { headers });
31212
- } catch {
31269
+ } catch (err) {
31270
+ const reason = err instanceof Error ? err.message : String(err);
31271
+ console.debug(`[admin/logs] miss dir=${dir} name=${fileName} reason=${reason}`);
31213
31272
  }
31214
31273
  }
31215
- return Response.json({ error: `Log not found: ${fileName}` }, { status: 404 });
31274
+ console.warn(`[admin/logs] not-found name=${fileName} searched=[${searched.join(",")}]`);
31275
+ return Response.json({ error: `Log not found: ${fileName}`, code: "NOT_FOUND" }, { status: 404 });
31216
31276
  }
31217
31277
  const seen = /* @__PURE__ */ new Set();
31218
31278
  const logs = {};
@@ -31221,7 +31281,9 @@ async function GET9(request) {
31221
31281
  let files;
31222
31282
  try {
31223
31283
  files = readdirSync5(dir).filter((f) => f.endsWith(".log"));
31224
- } catch {
31284
+ } catch (err) {
31285
+ const reason = err instanceof Error ? err.message : String(err);
31286
+ console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
31225
31287
  continue;
31226
31288
  }
31227
31289
  files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync7(resolve19(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
@@ -31230,8 +31292,10 @@ async function GET9(request) {
31230
31292
  const content = readFileSync20(resolve19(dir, name));
31231
31293
  const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
31232
31294
  logs[name] = tail.trim() || "(empty)";
31233
- } catch {
31234
- logs[name] = "(unreadable)";
31295
+ } catch (err) {
31296
+ const reason = err instanceof Error ? err.message : String(err);
31297
+ console.debug(`[admin/logs] read-fail name=${name} reason=${reason}`);
31298
+ logs[name] = `(unreadable: ${reason})`;
31235
31299
  }
31236
31300
  });
31237
31301
  }