scripts/vendor.sh clones upstream, rewrites @/ imports to relative paths, and applies scripts/apply-host.py. web/host.ts is ours and gets placed into the vendored tree, because upstream declined it. a script rather than a .patch, and that is not a preference. between cfde698 and 5c83ac6 — one day — upstream changed an import line, re-indented the component from 6 spaces to 8, and added an editAccess guard. a context diff fails on all three, none of which concern us. so every anchor matches structure with flexible whitespace and re-indents to whatever it finds, and a missing anchor stops the run loudly. all three prompt-export paths are wired, which is what upstream said a complete version needs. the other two clipboard writes are ShareMenu's share-link and ask-an-AI blurb, and the reason they are excluded is written down so the count does not read as the same oversight twice. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
118 lines
5.2 KiB
Bash
Executable File
118 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Re-vendor the M3E Canvas editor from upstream.
|
|
#
|
|
# ./scripts/vendor.sh [<git-ref>] default: main
|
|
#
|
|
# ── Why a script rather than a copy ──
|
|
#
|
|
# The vendored copy is NOT byte-identical to upstream, and it cannot be. Upstream imports through a
|
|
# `@/` path alias, and this platform already binds `@/*` to `src/apps/officer-web` and
|
|
# `@/components/*` to its own shared components. Left alone, `import { M3Node } from
|
|
# "@/components/M3Node"` inside the vendored editor would silently resolve to Officer's components
|
|
# directory — a wrong module rather than a build error, which is the worst way to be broken.
|
|
#
|
|
# So every import is rewritten to a relative path. That transformation is MECHANICAL and lives here,
|
|
# which is what keeps the copy reviewable: `git diff` after a re-vendor shows upstream's real changes,
|
|
# because the rewrite produces the same output for the same input every time.
|
|
#
|
|
# Nothing else is edited. Officer's own changes live outside `web/vendor/`, reached through
|
|
# `web/adapter.ts`.
|
|
set -euo pipefail
|
|
|
|
REF="${1:-main}"
|
|
UPSTREAM="https://github.com/lnkiai/m3e-canvas.git"
|
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
DEST="$HERE/web/vendor"
|
|
WORK="$(mktemp -d)"
|
|
trap 'rm -rf "$WORK"' EXIT
|
|
|
|
echo "cloning $UPSTREAM @ $REF"
|
|
git clone -q --depth 1 --branch "$REF" "$UPSTREAM" "$WORK/src"
|
|
SHA="$(git -C "$WORK/src" rev-parse HEAD)"
|
|
WHEN="$(git -C "$WORK/src" log -1 --format=%ad --date=short)"
|
|
|
|
rm -rf "$DEST"
|
|
mkdir -p "$DEST"
|
|
|
|
# lib/ and components/ only. `app/` is upstream's Next.js route and is deliberately NOT taken:
|
|
# app/page.tsx becomes web/vendor/Canvas.tsx below, and app/layout.tsx has no meaning here.
|
|
cp -r "$WORK/src/lib" "$DEST/lib"
|
|
cp -r "$WORK/src/components" "$DEST/components"
|
|
cp "$WORK/src/app/page.tsx" "$DEST/Canvas.tsx"
|
|
cp "$WORK/src/app/globals.css" "$DEST/globals.css"
|
|
cp "$WORK/src/LICENSE" "$DEST/LICENSE"
|
|
|
|
# lib/ai.ts and components/AiPanel.tsx ARE vendored, despite being the parts Officer least needs.
|
|
#
|
|
# The first attempt deleted them — they keep model-provider API keys in localStorage and call the
|
|
# provider from the browser, which Officer has no use for and would not do that way. But Canvas.tsx
|
|
# references them in about a dozen places, so deleting meant editing vendored code, and the rule one
|
|
# paragraph up says not to. A faithful copy that carries an unused module beats a doctored one that
|
|
# cannot be re-vendored.
|
|
#
|
|
# They stay inert: the panel does nothing without a key, and Officer's shell does not surface the
|
|
# entry point. See ../README.md, "What we do not use".
|
|
|
|
# ── the mechanical rewrite ──
|
|
# `@/lib/x` -> relative path to vendor/lib/x
|
|
# `@/components/x` -> relative path to vendor/components/x
|
|
python3 - "$DEST" <<'PY'
|
|
import os, re, sys
|
|
dest = sys.argv[1]
|
|
for root, _, files in os.walk(dest):
|
|
for name in files:
|
|
if not name.endswith((".ts", ".tsx")):
|
|
continue
|
|
path = os.path.join(root, name)
|
|
depth = os.path.relpath(root, dest)
|
|
prefix = "./" if depth == "." else "../" * len(depth.split(os.sep))
|
|
src = open(path, encoding="utf-8").read()
|
|
out = re.sub(r'(["\'])@/(lib|components)/', lambda m: f"{m.group(1)}{prefix}{m.group(2)}/", src)
|
|
if out != src:
|
|
open(path, "w", encoding="utf-8").write(out)
|
|
PY
|
|
|
|
# Officer's own changes to the vendored code. Kept OUT of this script so the copy above is exactly
|
|
# upstream, and applied here so one command reproduces the whole state.
|
|
python3 "$HERE/scripts/apply-host.py"
|
|
|
|
cat > "$DEST/PROVENANCE.md" <<PROV
|
|
# Vendored from lnkiai/m3e-canvas
|
|
|
|
| | |
|
|
| --- | --- |
|
|
| upstream | $UPSTREAM |
|
|
| ref | \`$REF\` |
|
|
| commit | \`$SHA\` |
|
|
| dated | $WHEN |
|
|
| licence | MIT — see \`LICENSE\` beside this file |
|
|
| vendored | $(date -u +%Y-%m-%d) by \`scripts/vendor.sh\` |
|
|
|
|
**Do not edit anything in this directory.** Officer's changes live outside it, reached through
|
|
\`web/adapter.ts\`. Editing here makes the next \`vendor.sh\` run either clobber the change or
|
|
produce a diff nobody can read.
|
|
|
|
## What was taken, and what was not
|
|
|
|
Taken: \`lib/\`, \`components/\`, upstream's \`app/page.tsx\` as \`Canvas.tsx\`, and \`globals.css\`.
|
|
|
|
Not taken: \`app/layout.tsx\` — a Next.js route shell with no meaning here.
|
|
|
|
\`lib/ai.ts\` and \`components/AiPanel.tsx\` ARE taken even though Officer does not use them. They
|
|
keep model-provider API keys in \`localStorage\`, which is not how anything here should work — but
|
|
\`Canvas.tsx\` references them throughout, so removing them would mean editing vendored code. A
|
|
faithful copy carrying an unused module beats a doctored one that cannot be re-vendored. They are
|
|
inert without a key, and the shell does not surface them.
|
|
|
|
## The one edit \`vendor.sh\` makes
|
|
|
|
Every \`@/lib/…\` and \`@/components/…\` import is rewritten to a relative path. This platform already
|
|
binds \`@/*\` to \`src/apps/officer-web\` and \`@/components/*\` to its own shared components, so an
|
|
unrewritten import resolves to the WRONG module rather than failing — silent breakage.
|
|
|
|
The rewrite is deterministic, so a re-vendor produces a readable diff of upstream's real changes.
|
|
PROV
|
|
|
|
echo "vendored $SHA ($WHEN) -> web/vendor/"
|
|
echo " $(find "$DEST" -name '*.ts' -o -name '*.tsx' | wc -l) source files"
|