Skip to main content
← Back to list
01Issue
BugShippedSwamp CLI
Assigneesstack72

Relationships

#582 Extension source: direct-content export scan only reads first 64 KiB, silently drops exports beyond it

Opened by jentz · 6/6/2026· Shipped 6/6/2026

Summary

swamp extension source add with the direct-content layout detects an extension by scanning each candidate .ts file for an export const model|vault|driver|datastore|report = … declaration. The scan only inspects the first 65,536 bytes (64 KiB) of the file. A valid extension whose export declaration begins beyond that point is silently not detected — source add reports "No extensions found …" and the extension never registers.

The same files load and run correctly once published and pulled (the manifest-driven path reads the declared entry directly), so this only bites the local-source "test before publish" workflow.

Environment

  • swamp 20260605.235921.0-sha.e3a85856
  • macOS (Darwin), Deno runtime
  • Reproduced with both the direct-content layout and an equivalent extensions/<kind>/ tree.

Impact

  • Large single-file extensions cannot be loaded from a local source. In one repo, a ~1,000-line model (its export const model at byte 33,736) loads fine, while a ~2,500-line report in a sibling dir (its export const report at byte 79,640) is invisible to source add.
  • The miss is silent — no swamp-warning: is emitted about a file that was read but truncated past an export, so it presents as "my extension is broken" rather than "the scanner didn't read far enough".

Reproduction (minimal, deterministic)

Generator — writes a valid report whose export const report begins at a chosen byte offset:

# gen.py — usage: python3 gen.py <target_byte_offset> <out.ts> <name>
import sys
target=int(sys.argv[1]); path=sys.argv[2]; name=sys.argv[3]
header=b"// padding\n"; opener=b"/* "; closer=b" */\n"
export=(f'export const report = {{\n  name: "{name}",\n  description: "x",\n'
        '  scope: "workflow",\n'
        '  execute: async () => ({ markdown: "ok", json: {} }),\n};\n').encode()
fill=target-(len(header)+len(opener)+len(closer))
open(path,"wb").write(header+opener+b"x"*fill+closer+export)
for T in 60000 65000 66000 70000; do
  d=$(mktemp -d); python3 gen.py "$T" "$d/report.ts" "@repro/scan$T"
  printf 'export@%s -> ' "$T"
  swamp extension source add "$d" --only reports --json 2>&1 | jq -r '.action // .error'
  swamp extension source rm "$d" >/dev/null 2>&1
done

Observed

export@60000 -> added
export@65000 -> added
export@66000 -> No extensions found at '…'. Expected … files declaring extension exports …
export@70000 -> No extensions found …

Edge bisection (byte range the export const report token occupies):

[65510..65529) -> DETECTED
[65517..65536) -> missed
[65525..65544) -> missed
[65536..65555) -> missed

The cutoff is the 64 KiB (65,536-byte) mark — the export token must fall fully within the first 64 KiB to be detected.

Expected

Either (a) scan the whole file — exports are routinely placed at the end, after types/helpers — or (b) if a read cap is intentional for performance, at minimum emit a swamp-warning: naming any file that contains an export-like token past the window, and have the source add "No extensions found" error mention the size cap, so the failure is not silent.

Workaround

Place the export const <kind> within the first 64 KiB (e.g. near the top of the file), or split helpers into sibling modules so the entry file stays small.

When the entry in an extensions/<kind>/ tree is a symlink to the real file, the extension also fails to load; replacing the symlink with a real copy works. The bundler appears not to follow symlinks. Flagging in case it shares a root cause with local-source loading; happy to split into its own report.

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 2 MOREREVIEW+ 3 MOREPR_MERGED+ 1 MORECONTRIBUTOR_NOTIFIED

Shipped

6/6/2026, 11:18:30 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack726/6/2026, 10:26:39 PM
Editable. Press Enter to edit.

stack72 commented 6/6/2026, 11:18:38 PM

Thanks @jentz for reporting this! The fix has been merged and a release is on its way. We appreciate your contribution to swamp.

Sign in to post a ripple.