* feat(npm): publish as @twigpine/zero
The npm package moves from @gitlawb/zero to @twigpine/zero, and everything
that finds Zero's GitHub repository by name now names Twigpine/zero.
Package name
- package.json, the lockfile and release-please use @twigpine/zero.
`repository` names Twigpine/zero: npm checks provenance against it, so a
publish from this repo with the old URL fails with E422. The homepage is
zero.twigpine.com.
- The name lives in package.json only. build-platform-packages.mjs names the
wrapper, platform versions, alias names and alias targets from it, and
bin/zero.js reads its own package.json for the alias it resolves and for
every reinstall hint. The Go constant npmPackageName is held equal to
package.json by a test.
Repository defaults
- The update check (DefaultRepository), install.sh, install.ps1, the npm
wrapper's fallback downloader, and the GitHub Action's zero-repo default
all used Gitlawb/zero. That name now belongs to an unrelated GitHub org, and
these paths download and run what they find there, so they point at
Twigpine/zero. Docs, README and issue-template links follow. The Go module
path (and so `go install github.com/Gitlawb/zero/...`) is unchanged here.
Publishing
- The two inline publish steps become scripts/npm/publish-packages.sh, which
reads the name from the assembled payloads, refuses to start when the
wrapper's aliases do not match the platform payloads, skips versions
already on the registry (so re-running a half-finished job is safe), and
publishes with --ignore-scripts. The dist-tag rules are unchanged.
internal/npmwrapper/publish_test.go runs it against a fake registry.
Docs explain the switch for existing installs: uninstall @gitlawb/zero first,
because both packages own the `zero` bin and npm refuses the second (EEXIST).
* feat(npm): publish 0.10.0 once more as @gitlawb/zero to point users at the new name
Deprecating @gitlawb/zero alone would strand every existing npm install.
0.9.0's `zero upgrade` runs `npm install -g @gitlawb/zero@latest`; with
nothing newer under that name npm installs nothing, prints no deprecation
warning (it only warns when it installs something), and Zero then reports
"updated via npm to 0.10.0" while staying on 0.9.0.
So this release goes out once more under the old name, as a bridge:
- The publish job assembles the same verified artifacts a second time with
the new `build-platform-packages.mjs --package-name @gitlawb/zero` and
publishes them with publish-packages.sh, after the @twigpine/zero publish.
A gate runs it only while @gitlawb/zero's latest is still 0.9.0 (or is
this version, on a re-run), so it happens once.
- The build knows its name from the package.json beside it. The Go side
reports InstallMethodNpmLegacy: `zero upgrade` refuses with the switch
steps before any release check (so it works offline too), and
`zero update --check` adds them whether or not an update is out.
- bin/zero.js prints the same steps after zero exits (the TUI would hide a
notice printed first), only when stderr is a terminal, and not for
`update`/`upgrade`, which print it themselves.
- Updating from 0.9.0 now installs a real version, so npm also shows the
deprecation message.
The steps say to uninstall @gitlawb/zero before installing @twigpine/zero:
both own the `zero` bin, npm refuses the second install with EEXIST, and a
forced install loses the bin when the old package is later removed (checked
against npm 11.16).
docs/NPM_PACKAGING.md has the maintainer runbook: bootstrap and trust the new
package, retarget the old one's trusted publisher for the bridge, then
deprecate @gitlawb/zero, revoke its publisher, and delete the bridge steps.
* fix(npm): only skip a publish when npm says the version is not there
publish-packages.sh treated any failed `npm view <name>@<version>` as "not
published". A transient network, auth or registry error on the re-run that the
skip exists for therefore published a version that was already out, and npm
rejected it with EPUBLISHCONFLICT; with the registry unreachable it published
blind. npm 11 reports every kind of missing (no such package, no such version,
including platform versions) as E404, so only E404 now means "not published".
Any other failure is retried three times and then stops the job before it
publishes anything, with npm's own error shown.
The test fake now answers a missing version with E404 the way npm does (it
returned an empty success before), and can fail lookups with a network error.
The two new tests fail on the old lookup: one with EPUBLISHCONFLICT after
transient failures, the other by publishing while the registry is unreachable.
Also renames the unused retry variable in the legacy-name gate step to `_`
(shellcheck SC2034), matching the script.
* fix(doctor): report missing npm native binary in wrapper
Co-authored-by: Cursor <[email protected]>
* fix(doctor): preserve JSON output for missing native binary
* fix(doctor): preserve doctor CLI behavior in wrapper fallback
Co-authored-by: Cursor <[email protected]>
* style: gofmt npmwrapper doctor fallback tests
Co-authored-by: Cursor <[email protected]>
* fix(doctor): reuse shared Bun recovery helpers in wrapper fallback
Extract bunRecoveryParagraph and related helpers so the doctor missing-binary text path and the generic wrapper bail share the same copy. Add regression tests with ZERO_WRAPPER_SIMULATE_BUN to guard against future drift.
Co-authored-by: Cursor <[email protected]>
---------
Co-authored-by: Cursor <[email protected]>
* feat(npm): ship the native binary as platform optionalDependencies
Replace the postinstall downloader with Codex-style platform packages:
suffixed versions of @gitlawb/zero (X.Y.Z-<platform>-<arch>) carrying the
binary, sandbox helpers, and the vendored agent-browser/tuistory tree,
referenced from the wrapper via npm: aliases in optionalDependencies.
The published wrapper has no lifecycle scripts and no dependencies, so
npm/Bun/pnpm installs are silent: no EBADENGINE from agent-browser's
node>=24 engines pin, no allow-scripts warnings, no network outside the
npm registry. The old downloader remains as a checksum-verified first-run
fallback for --omit=optional installs and unsupported platforms.
scripts/npm/build-platform-packages.mjs assembles the payloads from the
release archives at publish time: it materializes npm's symlink .bin
shims into regular sh shims (npm pack silently drops symlinks) and prunes
agent-browser's other-platform binaries (~65 MB per package). The publish
job uploads platform versions first under --tag platform, asserts the
latest dist-tag survived (platform versions are semver prereleases of the
wrapper version), then publishes the wrapper.
See docs/NPM_PACKAGING.md for the architecture and publishing rules.
* fix(npm): address PR review — LICENSE in payloads, dist-tag lookup guard, accurate fallback and platform docs
- Ship the repo LICENSE in both the wrapper and platform payloads (npm only
includes a license file physically present in the packed directory).
- Guard the platform-publish dist-tag lookup with || true so a transient
npm view failure (or a bootstrap publish with no latest tag) cannot abort
the job between the platform and wrapper publishes.
- Gate the wrapper's fallback downloader on the release matrix so platforms
with no asset (windows-arm64 and unknown combos) skip the spawn instead of
attempting it every run; keep deliberate retry-on-failure for supported
platforms and say so honestly in the notice and docs.
- Correct Windows support wording everywhere: x64 only, ARM runs under
emulation (README, README_ZH, INSTALL.md incl. the release-target list).
The Bun instructions told global installers to run the postinstall script
manually against the global install path, because trustedDependencies only
works in a project package.json. Current Bun has a simpler sanctioned path
that works for both project and global installs: `bun pm trust
@gitlawb/zero` (with -g for globals) runs the blocked postinstall after the
fact. Verified on Bun 1.3.14 on Windows 11: `bun pm -g trust @gitlawb/zero`
fetched the binary and `zero --version` runs.
Lead with that in README.md, README_ZH.md, and docs/INSTALL.md, keep
trustedDependencies and the manual installer as alternatives for project
installs and older Bun versions, and teach the wrapper's missing-binary
message the same commands for the Bun case.
Co-authored-by: Claude Fable 5 <[email protected]>
Bun does not run dependency lifecycle scripts by default, so the npm
wrapper's postinstall (which fetches the native Zero binary from GitHub
Releases) is silently skipped. The first run then fails with an
unhelpful "No native binary found" message that points at a source-only
build command, leaving Bun users stuck.
Add a Bun section to README.md and docs/INSTALL.md with the two working
install paths (run postinstall.mjs manually, or add the package to the
project's trustedDependencies). Rewrite the wrapper's missing-binary
error to give an actionable fix for everyone and a Bun-specific hint
when run under Bun, instead of only suggesting a source checkout.
* Add local control browser and terminal tools
Add configurable local browser, desktop, and terminal control helpers with packaged helper discovery for install and release flows.
Improve sandbox scope classification for local control commands and shared temporary paths.
Add structured browser actions, terminal session line input/key normalization/read support, and artifact capture for local-control outputs.
Tested: GOCACHE=/tmp/zero-go-cache go test ./internal/localcontrol ./internal/tools ./internal/cli ./internal/config -run 'Test.*LocalControl|TestTerminal|TestBrowser|TestDesktop|TestCapture'
Tested: GOCACHE=/tmp/zero-go-cache go test ./internal/localcontrol ./internal/tools ./internal/cli ./internal/config ./internal/agent
Tested: tuistory smoke launched bash, sent interactive input, waited for expected output, and captured a no-cursor snapshot
Tested: git diff --cached --check
* Fix npm wrapper helper manifest test on macOS
Canonicalize expected helper paths in the npm wrapper manifest test so macOS /var and /private/var temp path aliases compare correctly.
Tested: GOCACHE=/tmp/zero-go-cache go test ./internal/npmwrapper
Tested: git diff --check
* Harden local control review fixes
Respect resolved local-control config before tool listing and filter validation while preserving stream-json usage error ordering.
Harden browser, desktop, and artifact tool validation; guard Linux-only app launch behavior; clear stale helper manifests from the npm wrapper.
Make helper packaging lockfile-based with npm ci and add installer/package tests for helper staging.
Tested: focused local-control/tool/CLI/release/install/sandbox suite
Tested: isolated full go test ./...
Tested: macOS and Windows compile-only checks for touched packages