Skip to content
toy-forgePublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

6 Commits

Folders and files

Repository files navigation

@toy-forge/zcode

Publishes the ZCode Agent CLI as an npm package with a zcode bin, so it installs with npm i -g instead of a hand-written shell wrapper.

The upstream repo is vendored as a git submodule at vendor/ZCode; the CLI bundle is built from it and shipped inside this package.

Build

Requires git, pnpm and Node >= 22. The bundled CLI works on any Node 22+; building it does not need Node 24.

git submodule update --init --recursive
npm run build          # or: node scripts/prepare.mjs

npm run build does four things:

  1. pnpm install --frozen-lockfile and pnpm --filter @zcode/cli... build inside vendor/ZCode
  2. copies the artifacts into this package (see layout below)
  3. applies two guarded rewrites to its own copy of the bundle (see below)
  4. syncs version from apps/zcode-cli/package.json

prepack runs the same script, so npm pack / npm publish never ship a stale bundle.

pnpm i at this repo root is optional: it installs the runtime dependencies so node bin/zcode.js works locally, but they are only needed by consumers of the published package. Build dependencies live in the submodule.

Layout produced

lib/zcode.cjs                     CLI bundle (the real entry point)
lib/provider/zcode-builtin.json   built-in provider catalog
lib/tui/index.js                  TUI runtime (ESM bundle built from packages/tui)

lib/zcode.cjs keeps @zcode/tui, koffi and playwright-core external, and reads provider/zcode-builtin.json relative to its own directory.

@zcode/tui is private and not on npm, so it is not a dependency at all. The bundle's non-SEA TUI import is rewritten to a relative path (see below) and the runtime ships inside lib/. Its own non-@zcode imports (@mbears/opentui-core, @mbears/opentui-react, react, shiki) are declared as regular dependencies. scripts/prepare.mjs re-reads the emitted TUI bundle on every build and fails if upstream starts importing a package that is not declared.

Two rewrites on our copy of the bundle

The submodule stays a pristine checkout: upstream source is never edited, and everything this package changes lives in scripts/prepare.mjs as a guarded string replacement on lib/. Each one asserts that its literal occurs exactly once, so an upstream reshuffle fails the build loudly instead of silently shipping a different result. Both comment blocks document how to re-derive the literals after updating the submodule.

1. Dynamic workflows default to on

Upstream defaults dynamic workflows to disabled for standalone CLI runs (DEFAULT_CLI_WORKFLOW_MODE in apps/zcode-cli/packages/cli/src/workflow-mode.ts). This package flips it to alwaysOn so zcode and zcode tui match the desktop app:

const WORKFLOW_DEFAULT_PATTERN = 'DEFAULT_CLI_WORKFLOW_MODE = "disabled"';
const WORKFLOW_DEFAULT_REPLACEMENT = 'DEFAULT_CLI_WORKFLOW_MODE = "alwaysOn"';

The shipped diff against upstream is a single line, and --workflow-mode disabled still turns workflows off. Note this also applies to headless --prompt runs, which is why upstream keeps it off by default.

2. TUI module specifier

Without SEA the CLI loads the TUI with await import("@zcode/tui") (apps/zcode-cli/packages/cli/src/tui-runtime-loader.ts), and the bundle keeps that bare specifier because @zcode/tui is a build external. Since the package does not exist in any registry, the specifier is rewritten to point into lib/:

const TUI_IMPORT_PATTERN = 'import("@zcode/tui")';
const TUI_IMPORT_REPLACEMENT = 'import("./tui/index.js")';

The SEA branch of the same file uses its own node_modules/@zcode/tui/dist/index.js asset path and is intentionally left alone.

Both rewrites happen at build time rather than through a postinstall/patch-package step: install-time scripts are subject to npm's allow-scripts policy and may not run, and patching files inside a globally installed package would have to mutate npm's own tree.

Install

npm i -g @toy-forge/zcode             # once published
npm i -g ./toy-forge-zcode-0.17.1.tgz # from a local tarball

Behaviour

bin/zcode.js is a thin launcher:

  • re-execs Node with --no-experimental-ffi when the running Node has node:ffi (Node 26+). The bundled opentui would otherwise pick that backend, which does not implement usize, and TUI init throws Failed to initialize OpenTUI render library. Older Node rejects the flag, so it is probed first.
  • zcode with no arguments opens the TUI. Dynamic workflows are already on by default (see above), so no flags are injected; pass --workflow-mode disabled to opt out.
  • everything else is passed through unchanged: zcode doctor --json, zcode plugins list, zcode --prompt ..., etc.

Notes

  • Official plugins and skills are not seeded into this package. zcode plugins install fetches them from the marketplace; plugins list shows whatever is already in ~/.zcode/cli/plugins.
  • playwright-core is installed for --browser-use headless; a Chrome/Chromium is still required separately.
  • Data, credentials and configuration stay in ~/.zcode, shared with the desktop app.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages