merge: origin/main (v1.41.1.0 audit wave) into garrytan/daegu-v3

Conflicts resolved:
- VERSION: keep 1.42.0.0 (queue-advance past #1592's v1.41.1.0 claim,
  per CLAUDE.md workspace-aware ship rule)
- CHANGELOG.md: keep both entries — v1.42.0.0 Daegu wave on top,
  v1.41.1.0 audit wave below in reverse-chronological order
- package.json: bump version field to 1.42.0.0 to match VERSION

Auto-merged cleanly:
- browse/src/meta-commands.ts: both the screenshot-size-guard wiring
  from C16 (this branch) and the parsePdfFromFile JSON validation
  from PR #1592 (main) survive in the merged file. Verified by
  inspecting the imports + call sites + running both test surfaces
  green.
- All other v1.41.1.0 changes from main (scripts/build-app.sh sed
  hardening, mktemp fallback drops, security-classifier download
  cleanup, global-discover 64KB cap) pulled in unchanged.

Verified 77 wave + audit tests green after merge:
- browse/test/screenshot-size-guard.test.ts (7)
- browse/test/regression-pr1169-pdf-from-file-invalid-json.test.ts
- browse/test/security-classifier-download-cleanup.test.ts
- browse/test/find-browse.test.ts (5)
- test/gstack-paths.test.ts (9), test/gstack-gbrain-sync.test.ts (37)
- test/memory-ingest-no-put_page.test.ts (2)
- test/resolvers-gbrain-put-rewrite.test.ts (2)
- test/extension-pty-inject-invariant.test.ts (3)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-05-20 07:00:38 -07:00
13 changed files with 664 additions and 23 deletions
+13 -6
View File
@@ -273,16 +273,23 @@ function resolveClaudeCodeCwd(
return null;
}
function extractCwdFromJsonl(filePath: string): string | null {
export function extractCwdFromJsonl(filePath: string): string | null {
// Read a capped prefix so huge JSONL files don't blow up memory. 64KB
// comfortably fits the largest observed session headers; the old 8KB cap
// would sometimes fall inside a single long line and silently drop the
// project (JSON.parse failure on the truncated tail).
const MAX_BYTES = 64 * 1024;
const MAX_LINES = 30;
try {
// Read only the first 8KB to avoid loading huge JSONL files into memory
const fd = openSync(filePath, "r");
const buf = Buffer.alloc(8192);
const bytesRead = readSync(fd, buf, 0, 8192, 0);
const buf = Buffer.alloc(MAX_BYTES);
const bytesRead = readSync(fd, buf, 0, MAX_BYTES, 0);
closeSync(fd);
const text = buf.toString("utf-8", 0, bytesRead);
const lines = text.split("\n").slice(0, 15);
for (const line of lines) {
// Drop the final segment — it may be an incomplete line at the cap boundary.
const parts = text.split("\n");
const completeLines = parts.length > 1 ? parts.slice(0, -1) : parts;
for (const line of completeLines.slice(0, MAX_LINES)) {
if (!line.trim()) continue;
try {
const obj = JSON.parse(line);
+7 -1
View File
@@ -107,7 +107,13 @@ BATCH="$BATCH]"
[ "$COUNT" -eq 0 ] && exit 0
# ─── POST to edge function ───────────────────────────────────
RESP_FILE="$(mktemp /tmp/gstack-sync-XXXXXX 2>/dev/null || echo "/tmp/gstack-sync-$$")"
# Create response file atomically. If mktemp fails, refuse to continue rather
# than fall back to a predictable $$-based path (race + overwrite footgun).
RESP_FILE="$(mktemp "${TMPDIR:-/tmp}/gstack-sync-XXXXXX")" || {
echo "gstack-telemetry-sync: mktemp failed — skipping this run" >&2
exit 0
}
trap 'rm -f "$RESP_FILE"' EXIT
HTTP_CODE="$(curl -s -w '%{http_code}' --max-time 10 \
-X POST "${SUPABASE_URL}/functions/v1/telemetry-ingest" \
-H "Content-Type: application/json" \