OverviewFilesCommitsIssuesDocsReleasesPeers

favela-surface commits / 7025a0f

ci: build + publish on push (no ci.yaml meant every push was silently skipped)
pear-git-v3 exports a push, finds no .pear-git/ci.yaml and returns `skipped` without a log line, so 0.0.64 never published. Same steps as favela-host, plus two fixes the dry run (pgv3's own loadCIConfig/runSteps on a git archive) found: - the import guard globs only files that exist (no bin/ here); - the test runner installs the LOCKED dev graph (brittle 4.1.1), not the ranges: fresh brittle 4.5.0 pulls bare-structured-clone 2.x -> bare-type >=1.3 -> Bare >=1.32, and this machine runs Bare 1.28. Also declares b4a, imported by lib/router.js and lib/multipart.js and only resolving through hoisting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7025a0f32e548ab65966e1a8a959de3624f85d29
by plankatron <fleeky@gmail.com> · 2026-10-13T18:56:27.000Z

Changed files (3) +110 -2

.pear-git/ci.yaml +106 -0
……@@ -0,0 +1,106 @@
1# pear-git CI — auto-build + publish on `git push pear master`.
2#
3# Copied from favela-host's ci.yaml (install -> vendor -> guard -> tests -> publish). Before this file
4# favela-surface had none, so pear-git-v3 exported every push and SKIPPED it without a log line
5# (`ci-orchestrator.js`: no ci.yaml -> { skipped }) — 0.0.64 never published, and 0.0.63 and earlier
6# were published by hand. Its one file: sibling (favela-markdown) is vendored like the others'.
7#
8# NO daemon-boot smoke: CI steps are synchronous with a hard timeout, and a step that boots a
9# long-running daemon orphans the child when the timeout fires.
10
11steps:
12 - name: install deps (root closure)
13 run: npm install --production
14 timeout: 300
15
16 # Vendor LAST among the npm operations. CI git-archives only this repo, so each file: dep is a
17 # dangling symlink until it is copied in from the build machine's working tree, and whatever is
18 # checked out there ships to the fleet. Refuse unless each sibling HEAD is reachable from a hosted
19 # branch.
20 #
21 # ⛔ The SOURCE comes from the file: spec, not the package name. Two siblings live off the flat
22 # layout: hyper-identity2 is `file:../packages/hyper-identity2` and hyperident is
23 # `file:../repos/hyperident`. Looking them up as hyper-fleeky/<name> (ap-bridge's rule) finds
24 # neither. The spec is resolved against the canonical checkout, because the export in /tmp has no
25 # meaningful `..`.
26 - name: "vendor file: siblings into the closure"
27 run: |
28 HF=/storage/projects/code/hypercore-kb/hyper-fleeky
29 [ -d "$HF" ] || HF="$HOME/hyper-fleeky"
30 SIBS=$(node -e 'const d=require("./package.json");const a={...d.dependencies,...d.devDependencies};console.log(Object.entries(a).filter(([,v])=>String(v).startsWith("file:../")).map(([k,v])=>k+"="+v.slice(8)).join(" "))')
31 echo "siblings (derived from package.json): $SIBS"
32 [ -n "$SIBS" ] || { echo "no file: siblings found — package.json unreadable?"; exit 1; }
33 rc=0
34 for pair in $SIBS; do
35 pkg=${pair%%=*}; rel=${pair#*=}
36 SRC="$HF/$rel"
37 if [ ! -d "$SRC" ]; then echo " $pkg: $SRC NOT FOUND on the build machine — refuse"; rc=1; continue; fi
38 GD="$HOME/git-repos/$(basename "$rel").git"
39 if [ ! -d "$GD" ]; then echo " $pkg: no hosted repo at $GD — refuse"; rc=1; continue; fi
40 LOCAL=$(git -C "$SRC" rev-parse HEAD 2>/dev/null)
41 REFS=$(git --git-dir="$GD" for-each-ref --contains "$LOCAL" --format='%(refname:short)' refs/heads 2>/dev/null | tr '\n' ' ')
42 if [ -z "$REFS" ]; then echo " $pkg: $(echo $LOCAL | cut -c1-7) NOT in hosted history — refuse (push it)"; rc=1; continue; fi
43 echo " $pkg ($rel): $(echo $LOCAL | cut -c1-7) ok (on: $REFS)"
44 rm -rf "node_modules/$pkg" && cp -rL "$SRC" "node_modules/$pkg"
45 done
46 exit $rc
47 timeout: 180
48
49 # Declare-your-deps guard: an undeclared runtime import resolves locally through hoisting and then
50 # crash-loops the --production closure with MODULE_NOT_FOUND. Checks the DECLARATION, not the
51 # disk. Runtime code is index.js, bin/ and lib/; `#node:` specifiers are package imports and are
52 # skipped by the pattern.
53 - name: every direct import is declared
54 run: |
55 rc=0
56 # Only files that exist: favela-surface has no bin/, and grep on an unmatched glob fails the step.
57 FILES=$(ls index.js bin/*.js lib/*.js 2>/dev/null)
58 for spec in $(grep -hoE "from '[a-z0-9@][^']*'" $FILES \
59 | sed -E "s/.*from '([^']*)'/\1/" | sort -u); do
60 case "$spec" in
61 @*) m=$(echo "$spec" | cut -d/ -f1,2) ;;
62 *) m=$(echo "$spec" | cut -d/ -f1) ;;
63 esac
64 if node -e "const d=require('./package.json');process.exit(({...d.dependencies,...d.devDependencies})['$m']?0:1)"; then echo " ok: $m"
65 else echo " UNDECLARED: $m (from '$spec') — resolves on disk but is not in package.json"; rc=1; fi
66 done
67 exit $rc
68 timeout: 60
69
70 # Tests AFTER vendoring, against the exact tree about to be published. npm must not touch this
71 # tree now (it re-resolves and deletes hand-vendored directories), so registry devDependencies go
72 # into a SEPARATE prefix, only what the tree lacks is copied in, the suite runs with the tree's own
73 # brittle (brittle-bare runs tests in-process), and exactly those additions are removed again.
74 - name: tests (offline, against the vendored closure)
75 run: |
76 B=$(mktemp -d)
77 # ⛔ The LOCKED dev graph, every package at the version package-lock.json records — not the ranges
78 # in package.json. Resolved fresh, brittle ^4 became 4.5.0 (2026-10-09), whose
79 # bare-structured-clone 2.x needs bare-type >=1.3, and that needs Bare >=1.32; this machine runs
80 # Bare 1.28 and the tree pins bare-type 1.1.1, so the runner died before a single test. The
81 # lockfile's dev graph (brittle 4.1.1) is the one the suite already passes with locally.
82 SPECS=$(node -p 'const l=require("./package-lock.json").packages;Object.entries(l).filter(([k,v])=>v.dev&&/^node_modules\/(@[^/]+\/)?[^/]+$/.test(k)&&v.version).map(([k,v])=>k.slice(13)+"@"+v.version).join(" ")')
83 echo "test-only devDependencies: $SPECS"
84 npm install --prefix "$B" --no-audit --no-fund --no-save $SPECS >/dev/null 2>&1 || { echo "could not install: $SPECS"; exit 1; }
85 ADDED=""
86 for p in $(cd "$B/node_modules" && ls -A | grep -v -E '^\.'); do
87 case "$p" in
88 @*) for q in $(ls -A "$B/node_modules/$p"); do
89 if [ ! -e "node_modules/$p/$q" ]; then mkdir -p "node_modules/$p" && cp -r "$B/node_modules/$p/$q" "node_modules/$p/$q" && ADDED="$ADDED $p/$q"; fi
90 done ;;
91 *) if [ ! -e "node_modules/$p" ]; then cp -r "$B/node_modules/$p" "node_modules/$p" && ADDED="$ADDED $p"; fi ;;
92 esac
93 done
94 echo "overlaid for the test run only:$ADDED"
95 # The runner's path comes from brittle's own bin map: brittle 4 moved it from bin/bare.js
96 # (ap-bridge's 3.x) to brittle-bare.js at the package root.
97 RUNNER=node_modules/brittle/$(node -p 'require("./node_modules/brittle/package.json").bin["brittle-bare"]')
98 bare "$RUNNER" test/*.test.js; rc=$?
99 for p in $ADDED; do rm -rf "node_modules/$p"; done
100 rm -rf "$B"
101 exit $rc
102 timeout: 900
103
104 - name: pgh publish (content-addressed -> installable app)
105 run: pgh publish . --accept-conflict "automated CI publish; dep version-splits inherited from per-app lockfiles across the pgh ecosystem"
106 timeout: 300
package-lock.json +2 -1
……@@ -15,7 +15,8 @@
1515 "bare-os": "^3.9.3",
1616 "bare-path": "^3.1.2",
1717 "bare-process": "^4.5.1",
18 "favela-markdown": "file:../favela-markdown"
18 "favela-markdown": "file:../favela-markdown",
19 "b4a": "^1.8.1"
1920 },
2021 "bin": {
2122 "favela-surface": "index.js"
package.json +2 -1
……@@ -40,7 +40,8 @@
4040 "bare-path": "^3.1.2",
4141 "bare-process": "^4.5.1",
4242 "bare-fs": "^4.8.1",
43 "bare-crypto": "^1.11.1"
43 "bare-crypto": "^1.11.1",
44 "b4a": "^1.8.1"
4445 },
4546 "devDependencies": {
4647 "brittle": "^4.0.2"