Skip to content

Extract CLI scaffolding + remote proxy into witan-core; add publish/test CI#130

Merged
blarghmatey merged 4 commits into
mainfrom
worktree-witan-core-cli-scaffolding
Jul 16, 2026
Merged

Extract CLI scaffolding + remote proxy into witan-core; add publish/test CI#130
blarghmatey merged 4 commits into
mainfrom
worktree-witan-core-cli-scaffolding

Conversation

@blarghmatey

@blarghmatey blarghmatey commented Jul 16, 2026

Copy link
Copy Markdown
Member

What & why

Part of Extract witan-core shared package (wp-extract-witan-core-shared-package-e2660b), continuing after #129. Two extractions plus the missing CI/publish wiring.

1. CLI scaffolding → witan_core.cli (the cli extra)

witan and witan-code each carried divergent copies of the same setup scaffolding:

  • AgentName / AGENT_NAMES — supported coding-agent constants.
  • make_app — the --version-wired cyclopts app factory.
  • resolve_author--authorgit config user.name$USER"unknown".
  • report_install — the agent-config install-result printer; styled markup with a rich console, plain print without one (so witan-code keeps its plain output without a rich dependency).

agent-config-kit becomes a dep of the cli extra (supplies resolve_version + the InstallResult type).

2. Remote MCP-client stack → witan_core.remote (the remote extra)

ADR-0005 (#128, path a) added — in witan-council only — a client-side stack for the CLI to reach its deployed self over MCP. Extracted the transport-agnostic core so a future deployed witan-code reuses it instead of a third copy:

  • DeviceAuth (witan_core.remote.oidc) — OIDC device-authorization grant (RFC 8628) + 0600 token cache + transparent refresh, parameterized by cache path and login_hint.
  • RemoteMCPProxy (witan_core.remote.proxy) — mirrors a FastMCP server's tool surface over streamable-http (positional→name arg mapping, {"result": …} envelope unwrap, per-call bearer token). Server policy comes from subclass hooks: _is_admin_tool/_admin_error, _unknown_tool_error, _resolve_repo.

witan-council keeps its policy local via thin shims: the ~/.config/witan/tokens.json cache (+ WITAN_TOKEN_CACHE) and witan login hint; RemoteServerProxy subclasses the core with _ADMIN_ONLY + repo.detect. All CLI call sites and the login/logout/whoami + remote-proxy behavior are byte-identical.

Both servers declare the extras they use: witan → witan-core[cli,remote], witan-code → witan-core[cli]. witan-core imports neither server (leaf invariant holds).

3. CI / publish (gaps from #129)

  • witan-core-tests.yml — the package had no CI test job (mirrors agent-config-kit-tests.yml; hermetic suite, no binary step).
  • publish-witan-core.yml — the package had no PyPI publish workflow (mirrors publish-agent-config-kit.yml; version-gated, tags witan-core-v<version>).

Bumps witan-core 0.1.0 → 0.2.0 (new cli + remote modules).

Testing

  • witan-core: 74 passed (CLI scaffolding + 23 remote device-auth/proxy tests moved here).
  • witan (council): 484 passed (the delta vs 491 is the oidc coverage that moved to witan-core; witan keeps a shim-binding suite).
  • witan-code: 191 passed.
  • Smoke-tested unchanged: witan setup --dry-run / witan-code setup --dry-run (rich vs plain ->), witan --version, and witan login/whoami under unconfigured + misconfigured remote env.
  • prek run + uvx ruff@0.15.15 check/format clean.

🤖 Generated with Claude Code

Both servers' `setup` commands carried divergent copies of the same
scaffolding. Extract the shared surface into `witan_core.cli` (the `cli`
extra):

- AgentName / AGENT_NAMES — supported coding-agent constants.
- make_app — the `--version`-wired cyclopts app factory.
- resolve_author — --author → `git config user.name` → $USER → "unknown".
- report_install — the agent-config install-result printer; styled with a
  rich `console`, plain `print` without one, so witan-code keeps its exact
  plain output without importing rich just for that line.

witan-council and witan-code now import these instead of maintaining copies;
both servers' `setup --dry-run` output is byte-for-byte unchanged (rich `→`
vs plain `->`). agent-config-kit becomes a dep of the `cli` extra (supplies
resolve_version + the InstallResult type) — a valid leaf→leaf edge both
servers already have.

Also close two gaps: witan-core had no CI test job (add witan-core-tests.yml,
mirroring agent-config-kit's) and no PyPI publish workflow (add
publish-witan-core.yml). Bump witan-core 0.1.0 → 0.2.0 for the new module.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 16, 2026 16:01

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request extracts shared CLI scaffolding—including agent name constants, the application factory, author resolution, and installation reporting—from both the witan and witan-code servers into the shared witan-core package. This refactoring eliminates duplicate code and ensures consistent CLI behavior, supported by a new suite of unit tests. The review feedback suggests hardening the author resolution helper by catching OSError instead of FileNotFoundError to safely handle any OS-level execution failures when invoking git.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/witan-core/witan_core/cli.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR continues the witan-core extraction work by moving the duplicated CLI “setup” scaffolding from witan (witan-council) and witan-code into a shared witan_core.cli module, updating both servers to import the shared helpers, and adding missing CI workflows for witan-core (tests + PyPI publish).

Changes:

  • Added witan_core.cli with shared CLI primitives (AgentName/AGENT_NAMES, make_app, resolve_author, report_install) and added a dedicated test module for this shared behavior.
  • Updated witan and witan-code CLIs to use the shared witan_core.cli helpers instead of local duplicated implementations.
  • Added witan-core GitHub Actions workflows for tests and publishing; bumped witan-core version to 0.2.0 and updated changelog/locks accordingly.

Reviewed changes

Copilot reviewed 9 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/witan-core/witan_core/cli.py Introduces the shared CLI scaffolding helpers extracted from both servers.
packages/witan-core/tests/test_cli.py Adds tests to pin the shared CLI behavior (agent labels, author resolution, output, --version).
packages/witan-core/pyproject.toml Bumps version to 0.2.0 and adds agent-config-kit to the cli extra + test dependency group.
packages/witan-core/uv.lock Updates lockfile for new witan-core version and added dependencies.
packages/witan-core/CHANGELOG.md Documents the 0.2.0 release and the new witan_core.cli module.
mcp/servers/witan/witan/cli/setup_cmd.py Replaces duplicated agent-name/report/author logic with imports from witan_core.cli.
mcp/servers/witan/witan/cli/_common.py Switches to make_app factory for consistent --version wiring.
mcp/servers/witan/uv.lock Updates witan’s lockfile to witan-core 0.2.0 (and its CLI extra metadata).
mcp/servers/witan-code/witan_code/cli.py Switches to shared make_app, resolve_author, and report_install from witan_core.cli.
mcp/servers/witan-code/uv.lock Updates witan-code’s lockfile to witan-core 0.2.0 (and its CLI extra metadata).
.github/workflows/witan-core-tests.yml Adds CI test + ruff checks workflow for the witan-core package.
.github/workflows/publish-witan-core.yml Adds version-gated PyPI publish workflow and tags witan-core-v<version> after successful publish.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/witan-core-tests.yml
Comment thread packages/witan-core/witan_core/cli.py Outdated
ADR-0005 (path a) added, in witan-council only, a client-side stack for the
CLI to reach its *deployed* self over MCP. Extract the transport-agnostic core
into `witan_core.remote` (the `remote` extra: httpx + fastmcp) so a second
deployed server (e.g. witan-code) can reuse it instead of a third copy:

- `DeviceAuth` (witan_core.remote.oidc) — the OIDC device-authorization grant
  (RFC 8628) + 0600 token cache + transparent refresh, parameterized by cache
  path and `login_hint` (woven into "run `…`" messages).
- `RemoteMCPProxy` (witan_core.remote.proxy) — mirrors a FastMCP server's tool
  surface over streamable-http: positional→name arg mapping via inputSchema,
  `{"result": …}` envelope unwrap, per-call bearer token. Server policy is
  supplied by subclass hooks: `_is_admin_tool`/`_admin_error` (break-glass
  refusal), `_unknown_tool_error`, `_resolve_repo` (client-side repo).

witan-council keeps its policy local via thin shims: `witan/remote/oidc.py`
binds the `~/.config/witan/tokens.json` cache (+ `WITAN_TOKEN_CACHE`) and the
`witan login` hint; `witan/remote/proxy.py`'s `RemoteServerProxy` subclasses
the core with `_ADMIN_ONLY` + `repo.detect`. All CLI call sites
(cli/_common._srv, cli/auth, cli/__init__) and the `witan login/logout/whoami`
+ remote-proxy behavior are unchanged and byte-identical. witan-core imports
neither witan nor witan_code.

Both servers now declare the extras they use: witan → witan-core[cli,remote],
witan-code → witan-core[cli], floor bumped to >=0.2.

The exhaustive device-auth/cache/refresh and proxy arg-mapping tests move to
witan-core (23 tests); witan keeps a slimmer shim-binding suite.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@blarghmatey blarghmatey changed the title Extract CLI scaffolding into witan-core + add publish/test CI Extract CLI scaffolding + remote proxy into witan-core; add publish/test CI Jul 16, 2026
…ed fixture)

- config.py: point the oidc_audience doc at witan_core.remote.oidc.DeviceAuth._auth_params (moved out of witan.remote.oidc in this PR).
- witan-core-tests.yml: setup-uv input is enable-cache, not enable-caching — the typo silently disabled uv caching.
- test_remote_oidc.py: drop the unused auth fixture param from test_non_json_metadata_raises_clean_error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 23 changed files in this pull request and generated 3 comments.

Comment thread packages/witan-core/witan_core/remote/oidc.py
Comment thread packages/witan-core/witan_core/remote/oidc.py
Comment thread packages/witan-core/witan_core/remote/proxy.py
- resolve_author: catch OSError (not just FileNotFoundError) so any OS-level
  failure to spawn git degrades to the $USER/unknown fallback (gemini).
- RemoteMCPProxy._map_args: raise RemoteToolUnavailable with a clear message
  when a call passes more positionals than the deployed tool accepts, instead
  of an unhandled IndexError (copilot); add regression test.
- cli.py docstring: clarify the module never imports rich itself — the cli
  extra bundles it only for report_install's caller-supplied Console (copilot).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@blarghmatey
blarghmatey merged commit 3be5850 into main Jul 16, 2026
9 checks passed
@blarghmatey
blarghmatey deleted the worktree-witan-core-cli-scaffolding branch July 16, 2026 17:01
blarghmatey added a commit that referenced this pull request Jul 16, 2026
Cut a release of both servers. The [Unreleased] sections already carried the
new user-facing `--output-format` option (#127), making this a minor bump.
Also folds in the witan-core adoption from #130 (shared CLI scaffolding +
remote MCP-client stack; no behavior change; now depends on witan-core>=0.2).

Publishing is version-gated: merging this to main triggers publish-witan.yml
and publish-witan-code.yml to release 0.4.0 and tag witan-v0.4.0 /
witan-code-v0.4.0.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.

2 participants