Skip to content

refactor(cli): move the adapter contract, stub and Hermes into packages/seats - #2672

Closed
lilyshen0722 wants to merge 1 commit into
mainfrom
refactor/seats-package
Closed

lilyshen0722 wants to merge 1 commit into
mainfrom
refactor/seats-package

Conversation

@lilyshen0722

Copy link
Copy Markdown
Contributor

D62 extract-in-place, PR 1 of 5. No behaviour change.

What moves

packages/seats is new: private, type: module, Apache-2.0. It holds:

  • contract.js: the ADR-005 adapter contract in JSDoc, plus createRegistry and providerKeyEnvNames
  • upstream-refusal.js: moved whole
  • runtime-observation.js: controlsFromArguments and observeSpawn only. createRuntimeReporter posts to a Commonly instance, so it stays in the CLI.
  • seat-model.js: requireSeatModel(environment, name, required = false). The COMMONLY_REQUIRE_SEAT_MODEL read stays in the CLI.
  • adapters/stub.js: moved whole
  • adapters/hermes.js: now the factory createHermesAdapter(host). The host supplies memoryPreamble, effectiveTrust, seatModelRequired and profileRoot, and each has a neutral default.

The old CLI paths become one-line re-exports, and cli/src/lib/adapters/hermes.js binds the factory to Commonly's policy. The run loop, the registry, the other 7 adapters and every existing test are unchanged.

How it ships without publishing

cli/package.json adds "@commonlyai/seats": "file:../packages/seats" and lists it in bundleDependencies, so the package ships inside the @commonlyai/cli tarball.

Measured with npm 10.9 and 11.21:

  • after npm ci, npm pack carries all 8 package files;
  • without an install, npm pack exits 0 and silently leaves them out.

Two changes follow from that second result:

  • cli gets a prepack guard (scripts/require-bundled-seats.mjs) that refuses to pack when the bundle isn't installed;
  • npm-publish.yml runs npm ci --ignore-scripts before its compare step, not only before publish. Before this change the compare packed an uninstalled tree, so every run would have looked different from npm and triggered a publish. The workflow also now triggers on packages/seats/**.

Proof

New cli/__tests__/seats-package.test.mjs (6 tests):

  • The package imports only node built-ins and its own modules. Mutation check: adding import '../../../cli/src/lib/environment.js' fails it.
  • npm pack --dry-run lists every package source file under node_modules/@commonlyai/seats/. Mutation check: dropping bundleDependencies fails it.
  • The registry serves the bound adapters, and the CLI's Hermes has the same keys as a bare factory build.
  • A host-less Hermes takes the neutral defaults.
  • The registry refuses duplicate names.

Local results:

  • adapters.hermes, upstream-refusal, runtime-observation, attach and adapter-failure-scrub: 131/131, both with COMMONLY_REQUIRE_SEAT_MODEL unset and with it set to 1.
  • CLI suite: 1546 pass. The only failures were 2 suites that need backend/node_modules, which this worktree doesn't have and CI installs.
  • npm run lint is clean.

Jest resolves the symlinked file: dependency without any config change.

Walk: SRE will run the issued public BYO command once at this head, and the result goes here before any gate ask.

Ordering

This conflicts with #2582 in the Hermes adapter. #2582 should land first. I'll rebase this PR and carry its --in / 0.22 range change into packages/seats/src/adapters/hermes.js.

Design and import inventory: the D62 design note, kept outside the repo.

🤖 Generated with Claude Code

https://claude.ai/code/session_013ENddpGzhE7S8qjDSYAMuu

…es/seats

D62 extract-in-place, PR 1. No behaviour change.

packages/seats (private, Apache-2.0) now holds the adapter contract and
registry, the upstream-refusal naming, spawn observation, the seat-model
check and two adapters. Hermes becomes a factory that takes Commonly's
policy as a host object, so the package imports nothing from Commonly.
The old cli paths re-export or bind it, so no caller and no existing test
changes.

The CLI ships the package as a bundled file: dependency. Two publish fixes
come with it:
- npm pack on an uninstalled tree exits 0 and silently drops the bundle.
  cli's prepack now refuses that case.
- npm-publish installs before its compare step and triggers on
  packages/seats.

seats-package.test.mjs covers:
- the import boundary (mutation-checked);
- that the tarball carries every package file (mutation-checked);
- that the registry serves the bound adapters;
- the neutral defaults.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ENddpGzhE7S8qjDSYAMuu
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 136709a and 9d3e5ec.

Files ignored due to path filters: 1
  • cli/package-lock.json is excluded by !**/package-lock.json
Files selected for processing: 18
  • .github/workflows/npm-publish.yml
  • cli/__tests__/seats-package.test.mjs
  • cli/package.json
  • cli/scripts/require-bundled-seats.mjs
  • cli/src/lib/adapters/hermes.js
  • cli/src/lib/adapters/seat-model.js
  • cli/src/lib/adapters/stub.js
  • cli/src/lib/runtime-observation.js
  • cli/src/lib/upstream-refusal.js
  • packages/seats/README.md
  • packages/seats/package.json
  • packages/seats/src/adapters/hermes.js
  • packages/seats/src/adapters/stub.js
  • packages/seats/src/contract.js
  • packages/seats/src/index.js
  • packages/seats/src/runtime-observation.js
  • packages/seats/src/seat-model.js
  • packages/seats/src/upstream-refusal.js

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.

Walkthrough

The change extracts seat adapter contracts, helpers, and adapters into a private package. The CLI now uses and bundles that package, and the publish workflow tracks changes to it.

Changes: Seats package extraction

Layer / File(s) Summary
Package contracts and shared helpers
packages/seats/package.json, packages/seats/README.md, packages/seats/src/contract.js, packages/seats/src/seat-model.js, packages/seats/src/runtime-observation.js, packages/seats/src/upstream-refusal.js, packages/seats/src/index.js
The package defines adapter and host contracts, registry and provider-key helpers, seat-model validation, runtime observation, and upstream-refusal helpers. Its barrel file exports these helpers.
Stub and Hermes adapters
packages/seats/src/adapters/stub.js, packages/seats/src/adapters/hermes.js
The package adds the stub adapter and Hermes adapter. The Hermes adapter detects supported installations, validates its environment, processes JSONL events, and manages the subprocess.
CLI integration and package distribution
cli/src/lib/adapters/*, cli/src/lib/runtime-observation.js, cli/src/lib/upstream-refusal.js, cli/package.json, cli/scripts/require-bundled-seats.mjs, cli/__tests__/seats-package.test.mjs, .github/workflows/npm-publish.yml
The CLI re-exports implementations from the package and adds it as a bundled local dependency. A prepack check and tests cover package imports, adapter wiring, and tarball contents. The publish workflow tracks package changes and installs dependencies before comparison.

Priority: Low

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Refactor

Possibly related PRs

Merge Risk: Minimal · up to 9d3e5

This is an extraction of existing seat adapter code into a private package, with the CLI bundling it and the publish workflow tracking it. No actionable merge-blocking risk was identified. Normal CI and the author's pending rebase onto #2582 remain the remaining checks.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: moving the adapter contract, stub, and Hermes adapter into packages/seats.
Description check Passed The description is directly related to the changeset and explains the package extraction, CLI binding, bundling, workflow updates, tests, and reported validation results.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@lilyshen0722 lilyshen0722 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PASS at 9d3e5ec for the workflow and the prepack guard. Rhea's security gate is separate.

  • OIDC only: the publish job still has no NODE_AUTH_TOKEN and no secrets. reference. It keeps id-token: write and npm publish --provenance. The moved npm ci --ignore-scripts step is read-only and runs before the branch guard. The npm-release environment still gates it to main.
  • Guard: with @commonlyai/seats installed, npm pack --dry-run in cli/ includes node_modules/@commonlyai/seats/* and exits 0. With that link removed, the same command exits 1 from prepack with the "run npm ci in cli/" message.
  • cli seats-package.test.mjs: 6/6 at this head.

Not re-measured: the claim that npm pack on an uninstalled tree exits 0 without the guard. The guard does not depend on it.

Written by Sable, a Commonly agent — https://commonly.me/v2/pods/6a692a1be833c668acdb84cf

GATE: PASS

@lilyshen0722 lilyshen0722 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SECURITY gate for #2672 (refactor(cli): move the adapter contract, stub and Hermes into packages/seats) at 9d3e5ec. Head check: OPEN, not draft. Touches .github/workflows/npm-publish.yml, so this is the Tier 2 publish-workflow review.

Checked, both asked for:

  1. OIDC only, no token. The publish workflow has no secrets reference and no NODE_AUTH_TOKEN or _authToken (grep of the whole file at 9d3e5ec). The new Install step (npm ci --ignore-scripts) has no env. Publish still runs npm publish --provenance --access public with no token, and the job keeps id-token: write and contents: write only at job level. The trigger is push to main plus workflow_dispatch, with no pull_request, so untrusted PR code does not run here. Dispatch from a non-main ref is refused by the cmp step, and the npm-release environment binds it to main.
  2. The guard fails on a missing bundled dependency. In a fixture (cli with a file: dep and bundleDependencies), npm pack --dry-run with no install runs prepack and exits non-zero with "missing" from require-bundled-seats.mjs. After npm install --ignore-scripts, the symlinked node_modules/@commonlyai/seats packs in as 4 files, so the guard's existence check tracks a correct bundle.

Moving the install before the compare is a real fix. Before it, a compare on a tree with no node_modules could publish a CLI without its seats. node_modules is gitignored (.gitignore:10), so the git clean -fdq after the diff does not delete the install before publish.

Conditions and notes, none blocking:

  • --ignore-scripts is load-bearing. The job now holds id-token: write from the start and runs npm ci on every push that touches cli, including the skip path. That was already true of the publish path. Keep the flag. Dropping it would let an install script read the OIDC request env.
  • The guard checks that the seats manifest exists, not that its contents match. That holds for the symlink layout this PR uses. If someone later vendors a copy or changes the dep to a registry version, re-check the guard.
  • I did not inspect cli/package-lock.json integrity beyond the diff. That is the cli lane's review.

Written by Rhea, a Commonly agent — https://commonly.me/v2/pods/6a8f6dc7a1dccf2e02f31015

GATE: PASS at 9d3e5ec — the publish workflow stays OIDC-only with no token, the prepack guard fails when the bundled seats package is missing, and the install before compare is what keeps the tarball complete. Conditions: keep --ignore-scripts on the install step, and re-check the guard if the seats dependency changes from a symlink.

@lilyshen0722

Copy link
Copy Markdown
Contributor Author

BYO walk (rule 58) at head 9d3e5ec20: PASS, 2026-10-25 08:21Z.

  • CLI built from this head with cd cli && npm ci && npm pack (commonlyai-cli-0.1.155.tgz), then installed under a throwaway prefix. commonly --version prints 0.1.155. The run log itself prints no version line. The tarball carries node_modules/@commonlyai/seats (contract, stub, hermes).
  • Ran the listen snippet the BYO page issues, with no extra flags: export COMMONLY_API_URL, export COMMONLY_AGENT_TOKEN, commonly agent run <name> --adapter claude. The npm install line was swapped for the tarball install. It ran against a throwaway invite-only pod.
  • Bootstrapped the token file from the env token. The greeting turn posted (reply 84686). An @mention asking for PONG-2672 got exactly PONG-2672 (84690, via the tool, no echo).
  • Cleanup: token revoked, agent uninstalled, pod deleted (GET returns 404), local state removed.

@lilyshen0722

Copy link
Copy Markdown
Contributor Author

Closing as superseded: #2739 (merged 10-25) and the follow-ups #2762, #2766 and #2774 already moved the adapter contract, stub, Hermes, seat model, runtime observation and upstream refusal into packages/seats on main. Every file this PR adds is already there.

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