Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6c9e587
feat: implement hexagonal architecture domain layer
flyingrobots Jan 7, 2026
6f979c9
feat: implement multi-runtime support and harden domain architecture
flyingrobots Jan 7, 2026
1e1b209
chore: add CONTRIBUTING, SECURITY, NOTICE and CI workflow
flyingrobots Jan 7, 2026
abff5b9
feat: harden security, implement streaming output, and optimize perfo…
flyingrobots Jan 7, 2026
72c3274
feat: add reliable stream completion and harden command sanitizer
flyingrobots Jan 7, 2026
399518b
feat: architectural refinement v2.0.0 - unified streaming and exhaust…
flyingrobots Jan 7, 2026
a0a5f41
fix: remove explicit vitest imports to support multi-runtime globals
flyingrobots Jan 7, 2026
3fcebfe
docs: exhaustive update for v2.0.0 architecture and API
flyingrobots Jan 7, 2026
d3ab77b
docs: remove incorrect references to Continuum
flyingrobots Jan 7, 2026
44b7ab0
feat: core resilience and telemetry v2.1.0
flyingrobots Jan 7, 2026
581e913
feat(infra): refactor GitStream for binary support and optimize perfo…
flyingrobots Jan 7, 2026
0684d13
feat(domain): enhance domain logic and extensibility
flyingrobots Jan 7, 2026
2d6ba8f
refactor(domain): extract ExecutionOrchestrator service
flyingrobots Jan 7, 2026
c1b703c
docs: add recipes and finalize public API
flyingrobots Jan 7, 2026
d65c5ed
docs: finalize v2.2.0 documentation
flyingrobots Jan 7, 2026
72d0879
feat: refactor security and validation layer
flyingrobots Jan 7, 2026
4886f1e
refactor: core services for dependency injection and robust error han…
flyingrobots Jan 7, 2026
f778e84
feat: enhance command building and entry-point DI
flyingrobots Jan 7, 2026
4ce7f93
feat: implement high-level persistence and repository services
flyingrobots Jan 7, 2026
40551e9
docs: finalize refactor with commit lifecycle tutorial and service en…
flyingrobots Jan 7, 2026
7e80e23
refactor: core infrastructure for production stability
flyingrobots Jan 7, 2026
fa8aeea
feat: security layer and service decoupling
flyingrobots Jan 8, 2026
44c705e
refactor: orchestration and error-handling
flyingrobots Jan 8, 2026
9611271
feat: high-level domain persistence layer
flyingrobots Jan 8, 2026
c632f0b
docs: finalize public API and documentation for 2.0.0 release
flyingrobots Jan 8, 2026
fb105c7
fix: ci/cd docker compose command not found
flyingrobots Jan 8, 2026
cc20a62
fix: address all PR review comments from CodeRabbitAI
flyingrobots Jan 8, 2026
1cb0f8b
chore: final version sync and documentation updates for 2.7.0 release
flyingrobots Jan 8, 2026
c02fc22
refactor: fix backoff off-by-one and add safety throw in ExecutionOrc…
flyingrobots Jan 8, 2026
5158fb4
refactor: finalize multi-runtime refinements and validation hardening
flyingrobots Jan 8, 2026
26860aa
refactor: address ByteMeasurer validation and multi-runtime compatibi…
flyingrobots Jan 8, 2026
3e64f3c
refactor: finalize 2.7.0 release with hardened validation and multi-r…
flyingrobots Jan 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .devcontainer/bun/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "Bun (Git Stunts Plumbing)",
"build": {
"dockerfile": "../../Dockerfile.bun",
"context": "../.."
},
"customizations": {
"vscode": {
"extensions": [
"oven.bun-vscode",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
},
"postCreateCommand": "bun install",
"remoteUser": "root"
}
20 changes: 20 additions & 0 deletions .devcontainer/deno/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "Deno (Git Stunts Plumbing)",
"build": {
"dockerfile": "../../Dockerfile.deno",
"context": "../.."
},
"customizations": {
"vscode": {
"settings": {
"deno.enable": true,
"deno.lint": true,
"deno.unstable": true
},
"extensions": [
"denoland.vscode-deno"
]
}
},
"remoteUser": "root"
}
18 changes: 18 additions & 0 deletions .devcontainer/node/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "Node.js (Git Stunts Plumbing)",
"build": {
"dockerfile": "../../Dockerfile.node",
"context": "../.."
},
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"vitest.explorer"
]
}
},
"postCreateCommand": "npm install",
"remoteUser": "root"
}
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
.git
.crush
scripts
docker-compose.yml
Dockerfile.*
33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm install
- run: npm run lint

test-multi-runtime:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm install
- name: Run multi-runtime tests in Docker
run: npm test
50 changes: 50 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Architecture & Design

This project is built as a robust, low-level building block for Git-based applications. It follows strict engineering standards to ensure it is the most reliable Git plumbing library in the JavaScript ecosystem.

## 🏗️ Hexagonal Architecture (Ports & Adapters)

The codebase is strictly partitioned into three layers:

### 1. The Domain (Core)
Contains the business logic, entities, and value objects. It is **pure** and has zero dependencies on infrastructure or specific runtimes.
- **Entities**: `GitCommit`, `GitTree`, `GitBlob`.
- **Value Objects**: `GitSha`, `GitRef`, `GitFileMode`, `GitSignature`.
- **Services**: `CommandSanitizer` (security), `ExecutionOrchestrator` (retry/backoff), `GitErrorClassifier`, `GitPersistenceService`, `ByteMeasurer`.

### 2. The Ports (Contracts)
Functional interfaces that define how the domain interacts with the outside world.
- **`CommandRunner`**: A functional port defined in `src/ports/`. It enforces a strict contract: every command must return a `stdoutStream` and an `exitPromise`.

## 💉 Dependency Injection

Core services (`CommandSanitizer`, `ExecutionOrchestrator`) are designed as injectable instances. This allows developers to:
- Provide custom sanitization rules.
- Inject mock orchestrators for testing failure modes.
- Extend the `GitErrorClassifier` for specialized error handling.

## 🛡️ Defense-in-Depth Validation

We use **Zod** as our single source of truth for validation.
- **Schema Location**: All schemas reside in `src/domain/schemas/`.
- **Strict Enforcement**: No Entity or Value Object can be instantiated with invalid data. This ensures that errors are caught at the boundary, before any shell process is spawned.
- **JSON Schema Ready**: The Zod schemas are designed to be easily exportable to standard JSON schemas for cross-system interoperability.

## 🌊 Streaming-Only Model

In version 2.0.0, we eliminated the "buffered" execution path in the infrastructure layer.
- **Consistency**: Every runner behaves exactly the same way.
- **Memory Safety**: Large outputs (like `cat-file` on a massive blob) never hit the heap unless explicitly requested via `collect()`.
- **OOM Protection**: The `collect()` method enforces a `maxBytes` limit, preventing malicious or accidental memory exhaustion.

## 🧩 Engineering Mandates

1. **One File = One Class**: Every file in `src/` represents a single logical concept. No "utils.js" or "types.js" dumping grounds.
2. **Total JSDoc**: 100% of the public API is documented with JSDoc, enabling excellent IDE intellisense and automated documentation generation.
3. **Immutability**: All Value Objects are immutable. Operations that "change" a state (like `GitTree.addEntry`) return a new instance.
4. **No Magic Literals**: Constants like the `Empty Tree SHA`, default timeouts (120s), and buffer limits are exported from the port layer.

## 🧪 Quality Assurance

- **Multi-Runtime CI**: We don't just "test in Node". Our CI environment (via Docker Compose) runs the exact same test suite in Bun and Deno simultaneously.
- **Tests as Spec**: Our tests define the behavior of the system. A change in logic requires a change in the corresponding test to ensure the "red -> green" story is preserved.
97 changes: 97 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.7.0] - 2026-01-07

### Added
- **GitRepositoryService.save()**: Introduced a polymorphic persistence method that automatically delegates to the appropriate low-level operation based on the entity type (Blob, Tree, or Commit).
- **Commit Lifecycle Guide**: Created `docs/COMMIT_LIFECYCLE.md`, a step-by-step tutorial covering manual graph construction and persistence.

### Changed
- **Documentation Overhaul**: Updated `README.md` with enhanced security details and prominent links to the new lifecycle guide.
- **Process Isolation**: Hardened shell runners with strict environment variable whitelisting and support for per-call overrides.
- **Runtime Optimization**: Updated `ByteMeasurer` to use `Buffer.byteLength` where available and pinned Deno to 2.6.3 in development environments.
- **Improved Validation**: Enhanced `GitRefSchema` to strictly follow Git's naming rules, including better handling of control characters and '@' symbol sequences.

### Fixed
- **Node.js Shell Stability**: Resolved a critical bug in `NodeShellRunner` where processes were killed immediately if no timeout was specified.
- **Backoff Logic**: Fixed an off-by-one error in `ExecutionOrchestrator` that caused incorrect delay calculations during retries.
- **Type Safety**: Added type validation to `CommandSanitizer` to prevent `TypeError` when receiving non-string arguments.
- **Object Mapping**: Fixed a bug in `GitObjectType` where delta types were incorrectly mapped to strings instead of integers.
- **CI/CD Reliability**: Fixed GitHub Actions workflow by adding missing Node.js setup and dependency installation steps to the multi-runtime test job.
- **Persistence Accuracy**: Fixed incorrect tree entry type detection in `GitPersistenceService` that could cause tree corruption.

## [2.5.0] - 2026-01-05

### Added
- **GitCommandBuilder Fluent API**: Added static factory methods for all whitelisted Git commands (e.g., `.hashObject()`, `.catFile()`, `.writeTree()`) and fluent flag methods (e.g., `.stdin()`, `.write()`, `.pretty()`) for a more expressive command-building experience.

### Changed
- **GitPlumbing DI Support**: Updated the constructor to accept optional `sanitizer` and `orchestrator` instances, enabling full Dependency Injection for easier testing and customization of core logic.

## [2.4.0] - 2026-01-03

### Added
- **GitErrorClassifier**: Extracted error categorization logic from the orchestrator into a dedicated domain service. Uses regex and exit codes (e.g., 128) to identify lock contention and state issues.
- **ProhibitedFlagError**: New specialized error thrown when restricted Git flags (like `--work-tree`) are detected, providing remediation guidance and documentation links.
- **Dynamic Command Registration**: Added `CommandSanitizer.allow(commandName)` to permit runtime extension of the allowed plumbing command list.

### Changed
- **Dependency Injection (DI)**: Refactored `CommandSanitizer` and `ExecutionOrchestrator` into injectable class instances, improving testability and modularity of the `GitPlumbing` core.
- **Sanitizer Memoization**: Implemented an internal LRU-ish cache in `CommandSanitizer` to skip re-validation of identical repetitive commands, improving performance for high-frequency operations.
- **Enhanced Deno Shim**: Updated the test shim to include `beforeEach`, `afterEach`, and other lifecycle hooks for full parity with Vitest.

## [2.3.0] - 2026-01-01

### Changed
- **Validation Unification**: Completed the migration from `ajv` to `zod` for the entire library, reducing bundle size and unifying the type-safety engine.
- **Security Hardening**: Expanded the `EnvironmentPolicy` whitelist to include `GIT_AUTHOR_TZ`, `GIT_COMMITTER_TZ`, and localization variables (`LANG`, `LC_ALL`, etc.) to ensure identity and encoding consistency.
- **Universal Testing**: Updated the multi-runtime test suite to ensure 100% test parity across Node.js, Bun, and Deno, specifically adding missing builder and environment tests.

### Added
- **EnvironmentPolicy**: Extracted environment variable whitelisting into a dedicated domain service used by all shell runners.

## [2.2.0] - 2025-12-28

### Added
- **ExecutionOrchestrator**: Extracted command execution lifecycle (retry, backoff, lock detection) into a dedicated domain service to improve SRP compliance.
- **Binary Stream Support**: Refactored `GitStream.collect()` to support raw `Uint8Array` accumulation, preventing corruption of non-UTF8 binary data (e.g., blobs, compressed trees).
- **GitRepositoryLockedError**: Introduced a specialized error for repository lock contention with remediation guidance.
- **CommandRetryPolicy**: Added a new value object to encapsulate configurable retry strategies and backoff logic.
- **Custom Runner Registration**: Added `ShellRunnerFactory.register()` to allow developers to inject custom shell execution logic (e.g., SSH, WASM).
- **Environment Overrides**: `GitPlumbing.createDefault()` and `ShellRunnerFactory.create()` now support explicit environment overrides.
- **Repository Factory**: Added `GitPlumbing.createRepository()` for single-line high-level service instantiation.
- **Workflow Recipes**: Created `docs/RECIPES.md` providing step-by-step guides for low-level Git workflows (e.g., 'Commit from Scratch').

### Changed
- **Memory Optimization**: Enhanced `GitStream.collect()` to use chunk-based accumulation with `Uint8Array.set()`, reducing redundant string allocations during collection.
- **Runtime Performance**: Optimized `ByteMeasurer` to use `Buffer.byteLength()` in Node.js and Bun, significantly improving performance for large string measurements.
- **Development Tooling**: Upgraded `vitest` to version 3.0.0 for improved testing capabilities and performance.

## [2.1.0] - 2025-12-20

### Added
- **GitRepositoryService**: Extracted high-level repository operations (`revParse`, `updateRef`, `deleteRef`) into a dedicated domain service.
- **Resilience Layer**: Implemented exponential backoff retry logic for Git lock contention (`index.lock`) in `GitPlumbing.execute`.
- **Telemetric Trace IDs**: Added automatic and manual `traceId` correlation across command execution for production traceability.
- **Performance Monitoring**: Integrated latency tracking for all Git command executions.
- **Secure Runtime Adapters**: Implemented "Clean Environment" isolation in Node, Bun, and Deno runners, preventing sensitive env var leakage.
- **Resource Lifecycle Management**: Enhanced `GitStream` with `FinalizationRegistry` and `destroy()` for deterministic cleanup of shell processes.

### Changed
- **Entity Unification**: Refactored `GitTreeEntry` to use object-based constructors, standardizing the entire domain entity API.
- **Hardened Sanitizer**: Strengthened `CommandSanitizer` to block configuration overrides (`-c`, `--config`) globally and expanded the plumbing command whitelist.
- **Enhanced Verification**: `GitPlumbing.verifyInstallation` now validates both the Git binary and the repository integrity of the current working directory.

### Fixed
- **Deno Resource Leaks**: Resolved process leaks in Deno by ensuring proper stream consumption across all test cases.
- **Node.js Stream Performance**: Optimized async iteration in `GitStream` using native protocols.

## [2.0.0] - 2025-12-10

### Added
- Initial release of the plumbing library.
47 changes: 47 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment include:

* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at james@flyingrobots.dev. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq
39 changes: 39 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Contributing to @git-stunts/plumbing

First off, thank you for considering contributing to this project! It's people like you that make the open-source community such a great place to learn, inspire, and create.

## 📜 Code of Conduct

By participating in this project, you are expected to uphold our Code of Conduct. Please be respectful and professional in all interactions.

## 🛠️ Development Process

### Prerequisites
- Docker and Docker Compose
- Node.js (for local linting)
- **Windows Users**: Must use WSL or Git Bash to run shell-based test scripts locally.

### Workflow
1. **Fork the repository** and create your branch from `main`.
2. **Install dependencies**: `npm install`.
3. **Make your changes**: Ensure you follow our architectural principles (SRP, one class per file, no magic values).
4. **Write tests**: Any new feature or fix *must* include corresponding tests.
5. **Verify locally**:
- Run linting: `npm run lint`
- Run cross-platform tests: `npm test` (requires Docker)
6. **Commit**: Use [Conventional Commits](https://www.conventionalcommits.org/) (e.g., `feat: ...`, `fix: ...`).
7. **Submit a Pull Request**: Provide a clear description of the changes and link to any relevant issues.

## 🏗️ Architectural Principles
- **Hexagonal Architecture**: Keep the domain pure. Infrastructure details stay in `adapters`.
- **Value Objects**: Use Value Objects for all domain concepts (SHAs, Refs, Signatures).
- **Security First**: All shell commands must be sanitized via `CommandSanitizer`.
- **Environment Agnostic**: Use `TextEncoder`/`TextDecoder` and avoid runtime-specific APIs in the domain layer.

## 🐞 Reporting Bugs
- Use the GitHub issue tracker.
- Provide a minimal reproducible example.
- Include details about your environment (OS, runtime version).

## 📄 License
By contributing, you agree that your contributions will be licensed under its Apache-2.0 License.
6 changes: 6 additions & 0 deletions Dockerfile.bun
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM oven/bun:latest
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY . .
RUN bun install --ignore-scripts
CMD ["bun", "test"]
9 changes: 9 additions & 0 deletions Dockerfile.deno
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM denoland/deno:2.6.3

RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY . .

CMD ["deno", "task", "test"]
6 changes: 6 additions & 0 deletions Dockerfile.node
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM node:20-slim
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY . .
RUN npm install --ignore-scripts
CMD ["npm", "run", "test:local"]
16 changes: 16 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@git-stunts/plumbing
Copyright 2026 James Ross

This product includes software developed by James Ross (james@flyingrobots.dev).

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Loading