Commit Graph

13 Commits

Author SHA1 Message Date
Jordan Ritter dc72e9cac8 feat(cvdiag): Python _shared bootstrap module + 12-integration reachability wiring (L0-C) 2026-06-18 14:06:57 -07:00
Jordan Ritter b4a2b279d4 fix(showcase): copy manifest.yaml into frontend Docker stage for strands/spring-ai/llamaindex
The mirrored LGP homepage prerenders / and reads manifest.yaml at build
time; these 3 baselines use an explicit COPY of config files that omitted
manifest.yaml, breaking SSG export (same fix as pydantic-ai in #5125). The
other 6 baselines copy the dir wholesale and already include it.
2026-05-31 10:39:25 -07:00
Tyler Slaton 1209f1758c docs(strands): annotate lockfile regen in Dockerfile + retrigger Build Check
The previous push (cffb6547a) and lockfile-regen push (65a26ebc7)
did not appear to trigger Showcase: Build Check (PR) — the workflow
last ran on e7dcd3cf (the diagnostic-probe commit) and no subsequent
run is visible via `gh api .../actions/runs?head_sha=...`. The PR
checks page therefore still reflects the old strands failure with
the bad lockfile, even though that lockfile has been regenerated.

This commit:
1. Adds a one-line comment to the strands Dockerfile pointing at the
   lockfile-regen commit, so a future reader can find the context
   if Depot ever poisons that cache again.
2. Forces Showcase: Build Check (PR) to fire by changing a file the
   workflow's paths filter (`showcase/**`) matches.

No behavioural change — the comment is dropped from the final image
by Docker's normal handling, and the file content the build sees is
the same `FROM node:22-slim AS frontend` it always was.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:35:23 -07:00
Tyler Slaton 65a26ebc7a fix(strands, shell-docs): regenerate strands lockfile (was invalid JSON) + setup-concept test race
Two independent fixes:

1. strands package-lock.json was invalid JSON.

   Commit 00ce3a933 on main ("chore: ratchet showcase baseline to 95 +
   sync strands lockfile", May 19) produced a lockfile with trailing
   commas before closing braces — Node's V8 JSON parser (which npm
   uses internally) rejects it as "Expected double-quoted property
   name in JSON at position 1042" the moment `npm ci` tries to read
   it. npm surfaces this as "command can only install with an
   existing package-lock.json with lockfileVersion >= 1", which is
   misleading — the lockfile exists and declares lockfileVersion: 3,
   but it fails to parse before npm gets that far.

   The first strands `Showcase: Build & Push` run on main after that
   commit (2026-05-19T20:57:40Z) failed for the same reason; main's
   strands check has been broken since, but B&P runs are gated by
   paths-filter so subsequent commits that didn't touch
   `showcase/integrations/strands/**` simply skipped the strands job
   instead of failing. Our PR's `Showcase: Build Check (PR)` matrix
   re-runs strands on every PR push and surfaces the inherited
   breakage.

   Fix: delete the malformed lockfile and regenerate with
   `npm install --legacy-peer-deps --package-lock-only` against the
   existing package.json. The new file is valid JSON (verified with
   `node -e "JSON.parse(...)"`) and `npm ci` succeeds locally with
   it. Lockfile size dropped from 849577 to 491930 bytes — the prior
   sync had bloated entries on top of being malformed.

   Also reverts the Dockerfile probe and the split-COPY workaround
   added in earlier commits on this branch (e82a938a0, b56a9252d,
   e7dcd3cff). The probe was the right diagnostic — it printed the
   first 200 bytes of /app/package-lock.json and showed only
   "lockfileVersion: 3," before parse error, which pointed at the
   malformed JSON. With a valid lockfile, `COPY ... && npm ci` works
   on the simple Dockerfile shape and the workaround is no longer
   needed.

2. setup-concept.test.ts path-traversal test had a /tmp race.

   The fix landed in e82a938a0 wrote a decoy file via
   `path.dirname(tmp)` — which resolves to the system temp root
   (`/tmp` on Linux, `/var/folders/.../T` on macOS), not a per-test
   scratch dir. Two concurrent runs of the test (e.g.
   `vitest --watch` re-firing mid-edit, or a developer running tests
   in two terminals) would race on the same shared decoy path; the
   second's finally-cleanup could delete the first's decoy mid-test
   and mask a real path-traversal regression.

   Fix: mkdtemp a per-test `scratch` directory in beforeEach, nest
   `tmp` inside it, plant the decoy in `scratch`, and let afterEach's
   recursive rmSync of `scratch` handle cleanup. Removes the
   try/finally block entirely. Comment math also corrected (the test
   walks four `..` segments, not three).

Call-site enumeration:
  - Dockerfile: only the `Showcase: Build & Push` and `Build Check
    (PR)` workflows invoke this. Same `COPY ... && npm ci` shape as
    every other integration Dockerfile.
  - package-lock.json: consumed by `npm ci` only. New file generated
    by npm itself from the same package.json the previous lockfile
    targeted.
  - setup-concept.test.ts: no external consumers; helper variables
    `scratch`/`tmp` are module-local.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:23:13 -07:00
Tyler Slaton e7dcd3cff1 fix(strands): expand Dockerfile probe to diagnose Depot cache anomaly
The previous probe confirmed the lockfile is present in /app/ at
849KB and `test -s` passes. npm ci then immediately errors with
EUSAGE saying "command can only install with an existing
package-lock.json with lockfileVersion >= 1" — even though the file
clearly exists.

This commit prints additional state so the next failed run gives us:
- node + npm versions (rules out older npm rejecting lockfileVersion 3)
- the first 200 bytes of the lockfile (confirms content isn't
  corrupted / BOM / different encoding)
- the lockfileVersion parsed from JSON (confirms it's >= 1)

If npm ci still fails after this, the printed state will pinpoint
the exact divergence. Probe to be removed once root cause is known.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:15:09 -07:00
Tyler Slaton b56a9252d6 fix(strands): fuse COPY+npm ci probe to bypass Depot cache poisoning
Prior attempts (lockfile sync from main d38265bf7, splitting COPY into
two lines e82a938a0) did not unstick the strands build — the COPY
step reports success while the subsequent npm ci fails immediately
with EUSAGE (no package-lock.json), pointing at a Depot remote
BuildKit cache layer that surfaces with only package.json present.

This commit:
1. Switches the COPY back to the `COPY package*.json ./` glob form
   (changes cache key vs. the two-line split that failed).
2. Adds a probe RUN that `ls`-es /app and asserts package-lock.json
   is non-empty before invoking npm ci. If the file is missing,
   the probe fails loudly with a clear message instead of npm's
   opaque EUSAGE output.
3. Fuses the assertion + npm ci into a single RUN so any future
   cache replay must include both — partial cache hits can no
   longer surface only the COPY layer.

If this still fails after push, the probe output ("package-lock.json
missing or empty in build context") tells us definitively whether
the cache is dropping the file or whether npm ci has some other
quarrel. Either way we'll have a concrete next step instead of
re-running the same opaque error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:09:41 -07:00
Tyler Slaton e82a938a08 fix(shell-docs, strands): clipboard silent fail + path-traversal test + strands Depot cache-bust
Three independent fixes from CR Round 1 partition (bucket a):

- framework-overview.tsx: handleCopyCommand never awaited
  navigator.clipboard.writeText. A failed write (non-secure context,
  unfocused tab, permission denied) would still flip the "Copied!"
  indicator, so the user pastes nothing or stale content thinking the
  copy succeeded. Now awaits, branches on rejection, and logs.

- setup-concept.test.ts: the path-traversal-via-concept-arg test
  exercised the wrong code path. `concept = "../../secrets"` was
  normalized by path.join *before* reaching resolveWithinDir
  ("docs/setup/../../secrets.mdx" -> "secrets.mdx"), so the test
  passed because the decoy file didn't exist at the resolved location
  rather than because the path-traversal defense fired. The test
  would still pass if resolveWithinDir were deleted entirely.
  Reworked to use a 4-level traversal whose normalized form actually
  escapes integrationsRoot, and placed the decoy at the parent dir
  so a successful escape would resolve to a real file - the test now
  fails loudly if resolveWithinDir is removed.

- strands/Dockerfile: split `COPY package.json package-lock.json ./`
  into two explicit COPY lines to bust a poisoned Depot remote
  BuildKit cache entry on this branch. The poisoned layer surfaces
  with only package.json present, breaking `npm ci`. Lockfile sync
  from main (d38265bf7) wasn't enough since the cache key still
  matches the single-line instruction string. Splitting changes the
  instruction string and forces a fresh layer computation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:52:48 -07:00
Alem Tuzlak 03bed3b76b fix(showcase): regenerate 18 lockfiles in isolation; switch to npm ci
Lockfiles committed in 8ba692c42 were generated inside the monorepo
while pnpm's hoisted node_modules tree was present. npm-arborist
resolved transitive deps against pnpm's symlinks and wrote ~40
`../../../node_modules/.pnpm/...` paths into each lockfile's
`packages` map.

npm 10 can parse the JSON, but its arborist bombs out walking the
tree at those pnpm-relative entries with the misleading error:

    npm error code EUSAGE
    npm error The `npm ci` command can only install with an
    npm error existing package-lock.json or npm-shrinkwrap.json
    npm error with lockfileVersion >= 1.

`npm install --dry-run` surfaces the real cause:

    Cannot read properties of undefined (reading 'extraneous')

A fresh lockfile generated in an isolated container works.
- broken: 1259 packages, 43 with `../../../node_modules/.pnpm/...`
- fresh:  1321 packages, all `node_modules/...` paths

This commit regenerates every integration's lockfile inside an
isolated `node:22-slim` container via `npm install
--package-lock-only --legacy-peer-deps` and verifies with `npm ci`.
2026-05-19 12:12:57 +02:00
Alem Tuzlak 4b5f976016 fix(showcase): split COPY into two explicit lines + probe to diagnose CI failure
Glob form 'COPY package*.json ./' didn't fix CI -- only package.json
ended up in /app, despite the build context transferring 1.38 MB
(lockfile is 705 KB so it's clearly in the source).

This commit:
1. Splits the COPY into two unambiguous lines.
2. Adds a 'RUN ls -la /app/' probe before npm ci.

If the probe shows package-lock.json present in /app, the issue is in
npm ci discovery. If absent, the issue is in build context upload.
Probe to be reverted once root cause is known.
2026-05-19 11:38:08 +02:00
Alem Tuzlak 8ebd7dfe36 fix(showcase): use glob COPY package*.json ./ to bust poisoned Depot cache
CI failed on the 16 integrations whose explicit two-file COPY
`COPY package.json package-lock.json ./` hit a poisoned Depot remote
BuildKit cache entry: the cached layer reported CACHED but only
contained `package.json`, so the subsequent `npm ci` failed with
"command can only install with an existing package-lock.json".

Depot's cache had a layer indexed against the prior `COPY package.json
./` instruction; the new two-file instruction was matching it by some
internal cache-key collision. Two of 18 integrations (langgraph-python,
langgraph-typescript) passed only because they had a fully-cached
`RUN npm ci` layer from a sibling build that short-circuited the
broken COPY.

The glob form `COPY package*.json ./` produces an instruction string
that has never appeared in Depot's cache, so the layer is computed
fresh against the actual build context and includes both files. It
also reads cleaner than the explicit two-file enumeration.

No-Op when no cache poisoning is present -- the glob expands to exactly
package.json and package-lock.json on every integration (verified
locally; only those two files match per directory).
2026-05-19 11:19:24 +02:00
Alem Tuzlak 998be411bd fix(showcase): use lockfile-pinned npm ci in all integration Dockerfiles + reclaim BuildKit cache on build
## Root cause

17 of 18 integration Dockerfiles copy `package.json` but NOT
`package-lock.json`, then run `npm install --legacy-peer-deps`. Despite a
~700KB lockfile sitting in every directory, none of them are consulted at
build time. Only `built-in-agent` was already doing it right.

Effect on Windows / WSL2:

1. `npm install` re-resolves package versions from scratch on every
   rebuild, downloading ~1.1 GB into the build container's writable layer
   plus ~hundreds of MB of `~/.npm/_cacache` that lives in the same
   layer (BuildKit can't dedupe across builds because the layer hash
   varies with each non-deterministic resolution).
2. The npm install layer's BuildKit cache key is just `package.json`'s
   hash + base image — but with `npm install` (not `npm ci`) the install
   itself is non-deterministic, so a cached layer that resolved
   successfully can produce different node_modules trees than a fresh
   resolution. Worse, intermediate state from interrupted rebuilds
   (e.g. host OOM during `npm install`) is not reclaimed by `docker
   builder prune` until 24h later.
3. WSL2's `docker_data.vhdx` grows monotonically — it never shrinks
   until `wsl --shutdown` + `Optimize-VHD`. Repeated rebuilds compound
   into a VHDX that can reach hundreds of GB on the Windows host
   filesystem before any reclaim happens.

## Fix

Two-part:

1. **Lockfile-pinned, deterministic install** in all 18 Dockerfiles:
   ```
   COPY package.json package-lock.json ./
   RUN npm ci --legacy-peer-deps
   ```
   - `npm ci` is faster, deterministic, and writes ~half the temporary
     state of `npm install`.
   - The lockfile in COPY makes the install layer's BuildKit cache key
     stable across rebuilds, so once the layer is warm it actually stays
     warm.
   - Matches the pattern `built-in-agent` already uses.

2. **Reclaim dangling BuildKit cache in `bin/showcase build`** with a
   24h-window `docker builder prune --filter "until=24h"`. Keeps the
   warm cache for day-of work, reaps orphans from interrupted builds.

## Verification

```
for d in showcase/integrations/*/; do
  grep -E "^(COPY package|RUN npm)" "$d/Dockerfile" | head -2
done
```

now prints identical:
```
COPY package.json package-lock.json ./
RUN npm ci --legacy-peer-deps
```

for every integration.

## Out of band (cannot land in this PR)

- `docker volume prune -af` -- one-time recovery, ran locally, reclaimed
  16.11 GB from 236 anonymous Postgres volumes dating back to 2023.
- `Optimize-VHD` to compact the WSL2 docker_data.vhdx -- requires elevated
  PowerShell after `wsl --shutdown`. Each developer runs this themselves
  when their host drive gets tight; not something CI or this script can
  do.
2026-05-19 10:47:18 +02:00
Jordan Ritter e9a2e143de fix(showcase): add shared-tools symlinks and refactor imports
Replace sys.path.insert hacks in Python agent files with direct
imports via symlinks to shared/{python,typescript}/tools.
Update Dockerfiles, entrypoints, and configs to support the new
symlink-based tool resolution. Add PARITY_NOTES for frameworks
that have known gaps.
2026-04-28 07:50:03 -07:00
Jordan Ritter dd06dd89d1 refactor(showcase): rename packages/ to integrations/
The showcase framework directories better reflect their role as
integration examples rather than distributable packages.
Renames showcase/packages/ -> showcase/integrations/ and updates
the test docker-compose file reference accordingly.
2026-04-28 07:47:35 -07:00