Skip to main content

scoop-distribution

Maintain the Windows Scoop release channel: the per-repo manifest template and config, the publish-scoop-manifest job, and the shared xberg-io/scoop-bucket. Use this skill when editing anything under scripts/publish/*.json.tmpl or scripts/publish/scoop.json, when adding a CLI to the bucket, or when a Scoop install fails after a release.

معلومات المصدر

المستودع
xberg-io/agent-conventions
آخر نشاط في المصدر
٣٠ أغسطس ٢٠٢٦ في ١٢:٣٩
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٨
التفرعات
٢

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
scoop-distribution
description
Maintain the Windows Scoop release channel: the per-repo manifest template and config, the publish-scoop-manifest job, and the shared xberg-io/scoop-bucket. Use this skill when editing anything under scripts/publish/*.json.tmpl or scripts/publish/scoop.json, when adding a CLI to the bucket, or when a Scoop install fails after a release.
license
MIT
# Scoop Distribution Scoop is the Windows counterpart of the Homebrew tap. Each publishing repo owns one manifest template; the release pipeline renders it and pushes the result into `xberg-io/scoop-bucket`. The bucket is generated output — never hand-edit `bucket/*.json` there, because the next release of the owning repo overwrites it wholesale. Per repo: - `scripts/publish/scoop.json` — which manifests to render, and which release asset each SHA placeholder binds to - `scripts/publish/<app>.json.tmpl` — the manifest template - a `publish-scoop-manifest` job, mirroring `publish-homebrew-formula` in the same workflow ## The two escaping traps Templates are rendered with Python `string.Template.substitute`, so **every literal `$` in the manifest must be doubled**. Two of them appear in every template: - `"$$schema"` — a bare `"$schema"` is read as the placeholder `$schema` and raises `KeyError`, failing the render. Loud, so you find it immediately. - `$$version` inside `autoupdate` — this is Scoop's own placeholder, expanded by Scoop when it detects a new release. A bare `$version` there is **not** an error: it renders to the current release's version and silently freezes `autoupdate` on it forever. The second is the one that bites, because a frozen `autoupdate` looks correct in review and in the rendered manifest. Assert on it: the published `autoupdate` block must still contain a literal `$version`, while the top-level `architecture` URLs must contain a concrete number. ## `extract_dir` cannot be derived The repos do not package their Windows zips identically, and there is no rule that maps an asset name to its inner layout. Get this wrong and `bin` resolves to nothing — the manifest hashes and validates perfectly and installs a broken shim. | App | Zip layout | `extract_dir` | |-----|-----------|---------------| | `xberg` | nested, dir named after the asset | `xberg-cli-x86_64-pc-windows-msvc` | | `crawlberg` | nested, dir named after the asset | `crawlberg-cli-x86_64-pc-windows-msvc` | | `html-to-markdown` | nested, dir named after the asset | `cli-x86_64-pc-windows-msvc` | | `liter-llm` | nested, **version in the dir name** | `liter-llm-${version}-x86_64-pc-windows-msvc` | | `ts-pack` | **flat — the `.exe` is at the zip root** | omitted entirely | | `alef` | nested, dir named after the asset | `alef-x86_64-pc-windows-msvc` | Confirm with `unzip -l <asset>` against the actual release before trusting any of these; a repo can change its packaging without anyone noticing the manifest went stale. ## Render locally instead of waiting for CI A template change is cheap to verify end to end. This downloads the real asset, hashes it, and writes the manifest exactly as the release job would: ```bash git -C ../actions show origin/main:publish-scoop-manifests/scripts/render.py > /tmp/render.py mkdir -p /tmp/bkt/bucket GITHUB_WORKSPACE="$PWD" \ INPUT_BUCKET_DIR=/tmp/bkt \ INPUT_CONFIG_FILE="$PWD/scripts/publish/scoop.json" \ INPUT_TAG=v1.2.3 INPUT_VERSION=1.2.3 \ INPUT_GITHUB_REPO=xberg-io/<repo> INPUT_DRY_RUN=false \ python3 /tmp/render.py ``` Diff the result against the manifest currently in the bucket: for a released version it should come out byte-identical, and for a new one the only change should be the version and hashes. Set `INPUT_DRY_RUN=true` to render against a tag that does not exist yet — assets are replaced with a zero-SHA placeholder and the run still succeeds, which is what the dry-run pipeline does. ## Adding `scoop` to a repo's targets `release_scoop` comes from `alef release-metadata`, not from repo YAML. Two consequences: - `alef`'s `ALL_RELEASE_TARGETS` must already contain `scoop`, **and a release carrying it must be published**, before any repo can name the target. `parse_targets` hard-fails on an unknown name, so adding `scoop` to an explicit `available-targets:` list too early breaks that repo's release outright. - Repos that pass no `available-targets` default to all targets and need no edit. Repos that pass an explicit list must add `scoop` to it, but only after the alef release lands. Until then the wiring is inert and harmless: `release_scoop` resolves to an empty string, the job's gate is false, and the release report records the target as not enabled. ## Job shape Copy the repo's own `publish-homebrew-formula` rather than inventing one — in particular its five-attempt rebase/push loop. Six release pipelines push to the single shared bucket, so a concurrent release can land between checkout and push and reject it as non-fast-forward. Each repo touches only its own manifest, so rebasing onto the new tip and retrying is safe. Two deliberate differences from the Homebrew job: - **No `check-scoop` idempotency gate.** The render rewrites the manifest in place and the commit is guarded by `git diff --quiet bucket/`, so re-running a release is already a no-op. Pass no fourth argument to `require_publish` — there is no "already published" probe to consult. - **The job runs on dry runs; only the commit step is skipped.** Dry-run renders are the only pre-release exercise the template gets. Gating the whole job on `dry_run != 'true'` removes that safety net. ## Native dependencies Every CLI is a native MSVC build importing `VCRUNTIME140.dll`, so every manifest carries `"suggest": {"vcredist": "extras/vcredist2022"}`. Check the import table before adding an app — `llvm-objdump -p <exe> | grep 'DLL Name'`. A third-party hard import that is not bundled in the zip produces a binary that cannot start at all, and no amount of manifest correctness fixes it. `xberg.exe` imports `onnxruntime.dll` and depends on its publish job vendoring the DLL closure into the archive; Scoop's shim resolves DLLs from the app directory, so bundling is sufficient and no `depends` entry is needed. A runtime lookup on `PATH` (Tesseract, for OCR) belongs in `notes`, not in `depends`. ## What actually proves an install works Nothing on macOS or Linux does. Schema validation, a correct hash, and a byte-identical render all pass on a manifest that installs a binary which cannot launch. The only real proof is the `windows-latest` job in the bucket's `validate-manifests.yml`, which adds the checkout as a bucket, installs each changed app, and runs `<app> --version`. Treat a green local check as "nothing is obviously wrong", not as "this installs".
عرض على GitHub