Skip to content

publish pi-ilo-lang from the release workflow#151

Merged
danieljohnmorris merged 7 commits into
mainfrom
feature/pi-package
May 11, 2026
Merged

publish pi-ilo-lang from the release workflow#151
danieljohnmorris merged 7 commits into
mainfrom
feature/pi-package

Conversation

@danieljohnmorris
Copy link
Copy Markdown
Collaborator

Summary

  • New pi/ package (pi-ilo-lang) with two tools - ilo_run and ilo_repl - plus the canonical ilo skill, so the pi coding agent can write and run ilo without shelling out
  • One-line note in skills/ilo/SKILL.md pointing agents at those tools when they're inside pi
  • New publish-pi job in release.yml that npm-publishes pi-ilo-lang on every v* tag, mirroring how publish-npm works today

Why

Pi already runs the same skill I ship to Claude Code and Codex, but it has to shell out to ilo via the generic bash tool, which means a permission prompt per call and no structure on the output. A real pi extension fixes both. The REPL tool uses ilo's documented serv JSON loop so a session can be held open for iterative work, with a 5 minute idle timeout.

Behaviour notes

  • ilo_run resolves the binary as $ILO_BIN -> bundled node_modules/.bin/ilo -> ilo on $PATH
  • ilo_repl keeps a single ilo serv child per pi process, with one request and one response per send, matching the serv protocol in ilo --help
  • Both tools declare parameters with typebox, the same shape pi-web-access uses
  • Peer deps target @mariozechner/* to match the installed pi-coding-agent 0.66.x

Test plan

  • Type-check passes (verified locally against the installed @mariozechner/pi-coding-agent types under strict mode)
  • npm pack from pi/ produces a tarball that contains extensions/, skills/ilo/SKILL.md, README.md, LICENSE
  • After the next v* tag, publish-pi runs to completion and pi install npm:pi-ilo-lang resolves
  • Inside pi: ilo_run({ code: "+1 2" }) returns stdout 3
  • Inside pi: ilo_repl({ command: "start" }), then send with a small program, then stop, with the idle timer cleaning up if stop is skipped

ships two tools and the ilo skill so the pi coding agent can write
and run ilo code without shelling out:

- ilo_run: invoke `ilo <code|file> [func] [args...]`, return stdout,
  stderr, exit code as structured details
- ilo_repl: hold one long-lived `ilo serv` subprocess (start/send/stop)
  with a 5 minute idle timeout and 30 second per-request timeout

binary resolution: $ILO_BIN, then a bundled bin under the package,
then `ilo` on $PATH. parameters declared with typebox, matching the
pattern in pi-web-access. peerDeps target @mariozechner/* to match
the installed pi-coding-agent 0.66.x.
one-line addition: if the agent is running inside pi with
pi-ilo-lang installed, prefer the ilo_run and ilo_repl tools over
shelling out. agents outside pi ignore the line.
new publish-pi job mirrors publish-npm: sparse-checkout pi/ plus
skills/ilo/, copy SKILL.md and README into the package so the
canonical skill is the only source, npm version from the tag, npm
publish with the existing NPM_TOKEN. swallows "previously published"
the same way the existing job does so re-runs on an existing tag
are safe.

uses an env var for GITHUB_REF_NAME to avoid the workflow-injection
shape the security hook flagged.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

addressed findings from the PR review:

- ilo_run wraps runIlo in try/catch and surfaces ENOENT cleanly
  ("ilo binary not found, set ILO_BIN or install ilo") instead of
  letting the rejection escape the tool boundary
- ilo_repl wires the execute() AbortSignal through to sendToRepl
  so cancellation no longer waits for the 30s request timeout
- sendToRepl checks process.exitCode and stdin.writable before
  pushing a pending, attaches stdin error handler at startup, and
  removes the pending entry on timeout/abort so the queue does not
  drift if a request never gets a response line
- proc.stdout reader logs orphan response lines to stderr instead
  of silently dropping them, so a protocol drift is visible
- describeIloError centralises ENOENT messaging for both tools
- removed the committed pi/skills/ilo/SKILL.md and gitignored
  skills/ inside pi/ so the canonical skills/ilo/SKILL.md is the
  only source. CI continues to copy it into the package before
  npm publish

no behaviour changes to ilo_run on the happy path. strict TS
check still passes against the installed pi-coding-agent types.
pi/ has its own README scoped to the extension. the previous job
copied README.md from the repo root into pi/ before npm publish,
which would have shipped the language-level README in the pi
package. drop that cp; the sparse-checkout no longer needs the
top-level README either. LICENSE is still bundled in the package
from pi/LICENSE which was committed alongside pi/package.json.
second-pass review caught two real issues and one false alarm:

- runIlo (I1): the stdin write/end pair could throw synchronously if
  the child exits before we finish writing. wrap in try/catch and
  attach a no-op stdin error handler so EPIPE does not become an
  unhandled 'error' event. the existing close handler still resolves
  with whatever exit code the child reported.
- ilo_repl (I2): the previous stdin error handler shifted the head
  pending and rejected it. with pipelined sends that mis-attributes
  the failure. drop the shift; let the process 'close' / 'error'
  handlers drain every in-flight pending. stdin error handler stays
  but is now a no-op so EPIPE does not crash the process.

I3 was a false alarm: pi/LICENSE is already committed in pi/, so the
sparse-checkout pulls it. no copy step needed.
publish-pi previously had no needs: clause, which meant a failing
Rust build or release step would not block the pi package from
shipping. that could put pi-ilo-lang@X.Y.Z on npm pointing at a
tag whose binaries never made it onto github releases.

add needs: [release] to mirror publish-crates. drop the redundant
LICENSE entry from the sparse-checkout list since pi/LICENSE is
committed in the repo and pulled by sparse-checkout pi.
@danieljohnmorris danieljohnmorris merged commit 6dbcf2e into main May 11, 2026
4 checks passed
@danieljohnmorris danieljohnmorris deleted the feature/pi-package branch May 11, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant