Compare commits

..

4 Commits

Author SHA1 Message Date
Jarvis
af7dd3fa7c ci: re-trigger pipeline (flaky pglite WASM OOM in packages/db, unrelated)
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
The push/ci run for the prior commit failed only in packages/db's
src/migrate.test.ts with 'memory access out of bounds' inside the pglite
WASM module — a known-flaky in-memory-Postgres crash under CI memory
pressure. The pr/ci pipeline passed on the identical tree, and this PR
changes only a bash launcher script (no TS / no db package), so the
failure cannot originate here. Empty commit to re-run CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 00:04:41 -05:00
Jarvis
644d2805d2 fix(fleet): pre-trust claude agent workdir to clear the folder-trust gate (#644)
Fleet-launched Claude agents stall forever at Claude Code's one-time
"Is this a project you trust?" folder-trust prompt: there is no human in
the pane to answer it, yet the heartbeat keeps reporting "healthy" because
the pane process is alive — it's just blocked. This is the most common
fleet outage (F1 / premature stop).

--dangerously-skip-permissions does NOT bypass this gate, and neither does
`trustedProjectDirectories` in settings.json (both verified empirically on
2026-06-24). The only record the gate honors is the per-project entry in
~/.claude.json: projects["<dir>"].hasTrustDialogAccepted == true — exactly
what answering the prompt writes.

start-agent-session.sh now pre-seeds that record for the claude runtime
before launching the pane. The seeding is:
- claude-only (codex/pi have no such gate),
- idempotent (no-op when already trusted),
- atomic (tempfile + os.replace; never corrupts a partial/unreadable file),
- flock-serialized across concurrent agent launches sharing ~/.claude.json,
- best-effort (any failure is non-fatal — the agent still launches, worst
  case it falls back to the pre-fix behavior).

Verified end-to-end: with /home/jarvis untrusted, the modified launcher
flips hasTrustDialogAccepted to true and Claude boots straight to the ready
prompt with no gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 00:04:41 -05:00
16ae809442 fix(update): re-seed framework on version drift, not just in-command updates (#642) (#646)
All checks were successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
2026-06-24 05:04:34 +00:00
6980e40e51 fix(db): stop pglite migration tests flaking CI (timeout + WASM OOM) (#647)
Some checks failed
ci/woodpecker/push/ci Pipeline was canceled
ci/woodpecker/push/publish Pipeline was canceled
2026-06-24 05:04:28 +00:00
4 changed files with 104 additions and 0 deletions

7
.gitignore vendored
View File

@@ -15,3 +15,10 @@ infra/step-ca/dev-password
# Scratch dirs created by the framework git-wrapper shell test harnesses
.mosaic-test-work/
# Transient config files vite/vitest/esbuild write next to a *.config.ts while
# loading it, then unlink. They are untracked but were not ignored, so turbo's
# package traversal hashed them and intermittently failed CI with "Package
# traversal error: ... .timestamp-*.mjs: No such file or directory" when the
# file vanished mid-scan. Ignoring them removes the race.
*.timestamp-*.mjs

View File

@@ -28,6 +28,7 @@ export default tseslint.config(
'apps/web/e2e/helpers/*.ts',
'apps/web/playwright.config.ts',
'apps/gateway/vitest.config.ts',
'packages/db/vitest.config.ts',
'packages/storage/vitest.config.ts',
'packages/mosaic/__tests__/*.ts',
'tools/federation-harness/*.ts',

View File

@@ -4,5 +4,22 @@ export default defineConfig({
test: {
globals: true,
environment: 'node',
// The migration suite spins up a real PGlite (WASM Postgres) instance per
// test and applies the full drizzle migration set. Each case legitimately
// takes ~5s locally and considerably longer on CI, where turbo runs many
// packages' test suites concurrently. The 5s vitest default then expires
// mid-migration and the run fails as a phantom "Test timed out in 5000ms"
// (often surfacing the underlying WASM `memory access out of bounds` when
// the heap is starved). Give migrations real headroom.
testTimeout: 120_000,
hookTimeout: 120_000,
// Each PGlite instance carries a multi-hundred-MB WASM heap. Running test
// files in parallel forks multiplies that peak and is what tips the CI
// runner into the WASM OOM. A single fork keeps only one instance resident
// at a time — slightly slower, but deterministic.
pool: 'forks',
poolOptions: {
forks: { singleFork: true },
},
},
});

View File

@@ -122,6 +122,85 @@ fi
mkdir -p "$MOSAIC_AGENT_WORKDIR"
# ── Pre-trust the workdir for the Claude runtime ─────────────────────────────
# Claude Code shows a one-time "Is this a project you trust?" folder-trust gate
# the first time it opens a directory. A fleet-launched agent has no human to
# answer it, so the pane stalls forever at the prompt while its heartbeat keeps
# reporting "healthy" (the pane process IS alive — it's just blocked).
#
# IMPORTANT: --dangerously-skip-permissions does NOT bypass this gate, and
# neither does `trustedProjectDirectories` in settings.json (verified empirically
# 2026-06-24). The ONLY thing the gate honors is the per-project record in
# ~/.claude.json: projects["<dir>"].hasTrustDialogAccepted == true (exactly what
# answering the prompt writes). So we pre-seed that record here.
#
# Idempotent, atomic, best-effort: any failure is non-fatal (the agent still
# launches — worst case it stalls on the gate, i.e. the pre-fix status quo).
# Only the claude runtime needs this; codex/pi have no such gate.
_ensure_claude_workdir_trusted() {
local workdir="$1"
# The path claude keys on is the resolved cwd it is launched in.
local rp
rp=$(cd "$workdir" 2>/dev/null && pwd -P) || rp="$workdir"
# ~/.claude.json lives next to the claude config dir; honor CLAUDE_CONFIG_DIR.
local claude_json="${MOSAIC_CLAUDE_JSON:-${CLAUDE_CONFIG_DIR:+$CLAUDE_CONFIG_DIR/.claude.json}}"
claude_json="${claude_json:-$HOME/.claude.json}"
if ! command -v python3 >/dev/null 2>&1; then
echo "WARNING: python3 not found; cannot pre-trust '$rp' for claude (agent may stall on the folder-trust gate)" >&2
return 1
fi
# Serialize concurrent agent launches that share ~/.claude.json (flock if available).
local lock="${claude_json}.mosaic-lock"
_seed() {
MOSAIC_CJ="$claude_json" MOSAIC_TRUST_DIR="$rp" python3 - <<'PY'
import json, os, sys, tempfile
cj = os.environ["MOSAIC_CJ"]
d = os.environ["MOSAIC_TRUST_DIR"]
try:
data = json.load(open(cj)) if os.path.exists(cj) else {}
if not isinstance(data, dict):
data = {}
except Exception:
# Never corrupt an unreadable/partial file — bail without writing.
sys.exit(2)
projects = data.setdefault("projects", {})
entry = projects.get(d)
if not isinstance(entry, dict):
entry = {}
projects[d] = entry
if entry.get("hasTrustDialogAccepted") is True:
sys.exit(0) # already trusted — nothing to do
entry["hasTrustDialogAccepted"] = True
tmp_dir = os.path.dirname(cj) or "."
fd, tmp = tempfile.mkstemp(dir=tmp_dir, prefix=".claude.json.mosaic.")
try:
with os.fdopen(fd, "w") as f:
json.dump(data, f, indent=2)
os.replace(tmp, cj) # atomic
except Exception:
try:
os.unlink(tmp)
except OSError:
pass
sys.exit(3)
PY
}
if command -v flock >/dev/null 2>&1; then
( flock 9; _seed ) 9>"$lock" 2>/dev/null || _seed
else
_seed
fi
}
case "$MOSAIC_AGENT_RUNTIME" in
claude)
_ensure_claude_workdir_trusted "$MOSAIC_AGENT_WORKDIR" \
|| echo "WARNING: could not pre-trust workdir for claude agent $AGENT_NAME" >&2
;;
esac
# ── Launch the tmux session (no exec — we continue to wire the heartbeat) ────
_tmux new-session -d -s "$AGENT_NAME" -c "$MOSAIC_AGENT_WORKDIR" \
bash -c "$PANE_SHELL_SNIPPET"