Skip to content

feat: @devframes/service-git wire service + git plugin refactor - #263

Merged
antfu merged 3 commits into
mainfrom
feat/service-git
Aug 19, 2026
Merged

feat: @devframes/service-git wire service + git plugin refactor#263
antfu merged 3 commits into
mainfrom
feat/service-git

Conversation

@antfubot

Copy link
Copy Markdown
Collaborator

What

Extracts the git plugin's git utilities into a new @devframes/service-git wire service (a peer of service-open/service-shiki) and refactors plugins/git to consume it. Adds one small core mechanism — DevframeDefinition.snapshotRpc — so a devframe can bake an RPC it doesn't own into its static build.

@devframes/service-gitdevframes:service:git

createGitService({ cwd? }) → node API + devframes:service:git:* RPC + client advertisement.

  • Typed ops: status, log, show, diff, branches, stage, unstage, commit — the exact command-building + output parsing lifted from the plugin, now framework-neutral. The execFile wrapper and parsers stay internal; no raw git passthrough over RPC.
  • Single repo fixed at installcwd defaults to the context cwd, repo root discovered once (rev-parse --show-toplevel, memoized).
  • Write ops always exposed — authorization is the host's connection-trust boundary, not a service flag. Client-supplied revisions are guarded (isSafeRevision).
  • Defines no dump/snapshot — stays live-only.
  • Consumers get the node API in-process (ctx.services.get('@devframes/service-git')) and the same ops over RPC; types (GitStatus, GitDiff, CommitDetail, …) exported from the package and contributed to the RPC/scope declaration merges.

Core: DevframeDefinition.snapshotRpc

Opt an RPC function a devframe doesn't own (a service's) into the static-build dump, since the service declares no dump. Each entry is a bare method id (bakes the no-arg call) or { method, inputs } where inputs is argument-tuples or an async (ctx) => tuples provider (so it can enumerate at build time via the service node API). createBuild resolves these after setup and runs the target's own handler per tuple; the first tuple's result is the fallback. Exported applySnapshotRpc; DF0072 warns on a missing target.

plugins/git refactor

  • Deletes src/node/git.ts and the whole src/rpc/ layer — no git logic left in the plugin.
  • Declares the service (cwd from repoRoot computed at factory time) and opts the read ops into snapshotRpcstatus/branches/diff bake their no-arg call, log bakes the 200-commit head, show is enumerated per commit (patch-less) at build time via the service node API.
  • The React SPA calls devframes:service:git:* directly and imports types from @devframes/service-git.
  • Drops --write — writes are always available, protected by who-can-connect (matches the repo's security model).

Validation

  • pnpm lint && pnpm knip && pnpm test && pnpm typecheck && pnpm build all green (1226 tests, 110 files).
  • New tests: services/git covers every op + non-repo degradation + revision-injection safety + scoped RPC; plugins/git keeps an integration test (service RPC over the dashboard server), a write round-trip, and a snapshotRpc build-baking test; devframe core gains snapshotRpc coverage (string/inputs/provider + DF0072). API snapshots regenerated.

Created with the help of an agent.

Extract the git plugin's git utilities into a new @devframes/service-git
wire service and refactor the plugin to consume it.

- services/git: createGitService({ cwd? }) → node API + devframes:service:git:*
  RPC (status/log/show/diff/branches/stage/unstage/commit) + advertisement.
  Single repo fixed at install (defaults to ctx.cwd, root discovered once).
  Exec wrapper + parsers stay internal; typed ops only, no raw passthrough.
  Write ops always exposed — authorization is the host's connection-trust
  boundary. Defines no dump/snapshot of its own.
- core: DevframeDefinition.snapshotRpc lets a devframe bake an RPC it does
  not own (a service's) into its static build — string (no-arg) or
  { method, inputs: tuples | async (ctx) => tuples }. createBuild applies it
  before collecting; exported applySnapshotRpc; DF0072 warns on a missing
  target.
- plugins/git: drops its node/git.ts + rpc layer and all git logic; declares
  the service (cwd from repoRoot at factory time) and opts the read ops into
  snapshotRpc (show enumerated at build time via the service node API). The
  React SPA calls devframes:service:git:* directly and imports types from
  @devframes/service-git. Drops --write — writes are always available,
  protected by the connection trust boundary.
- docs: service-git in the built-in services list; snapshotRpc definition
  field; git plugin README.
@netlify

netlify Bot commented Aug 19, 2026

Copy link
Copy Markdown

Deploy Preview for devfra ready!

Name Link
🔨 Latest commit d0b2b7c
🔍 Latest deploy log https://app.netlify.com/projects/devfra/deploys/6a8531eaa182d20008d6edda
😎 Deploy Preview https://deploy-preview-263--devfra.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Group the RPC static-build opt-in under a new `rpc` config object:
`DevframeDefinition.rpc.snapshot` (new `DevframeRpcOptions`) replaces the
top-level `snapshotRpc`. Entry types and the `applySnapshotRpc` build
helper are unchanged; the git plugin, build adapter, DF0072 message, tests,
and docs are updated to the new shape.
The next-devframe-hub e2e asserted `devframes_plugin_git_status`; git's
agent-flagged reads now live on `@devframes/service-git`, so the hub MCP
surfaces `devframes_service_git_status`. Also assert the service exposes its
agent-flagged status op on the agent surface.
@antfu
antfu merged commit 01d8d08 into main Aug 19, 2026
11 of 12 checks passed
@antfu
antfu deleted the feat/service-git branch August 19, 2026 04:35
antfubot added a commit that referenced this pull request Aug 19, 2026
Reconcile the in-house diff renderer with #263's @devframes/service-git
refactor: the shared git types (GitDiff, FileStatusCode, CommitDetail) now
come from @devframes/service-git, and the RPC scope moved to
devframes:service:git:*. Combine the two service declarations (service-git +
service-shiki) into one array on the git devframe, and drop the leftover
@pierre/diffs/@pierre/theme lockfile entries.
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