WIP: A simple cli for daily tangled use cases and AI integration. This is for my personal use right now, but happy if others get mileage from it! :)
at pull-request-format-testing 319 lines 17 kB view raw view rendered
1*** THIS IS A TEST CHANGE TO BE USED FOR TESTING THE TANGLED PULL REQUEST ARTIFACTS *** 2 3This sentence was added in a second PR so I can see how it works. 4 5# Tangled CLI: Architecture & Implementation Plan 6 7## Project Overview 8 9**Goal:** Create a context-aware CLI for tangled.org that bridges the gap between the AT Protocol (XRPC) and standard Git. 10 11**Philosophy:** Follow the **GitHub CLI (gh)** standard: act as a wrapper that creates a seamless experience where the API and local Git repo feel like one unified tool. 12 13## Prior Art Analysis: GitHub CLI (gh) vs. Tangled CLI 14 15| Feature | GitHub CLI (gh) Approach | Tangled CLI Strategy | 16| :------------- | :--------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------- | 17| **Context** | Infers repo from .git/config remote URL. | **Must-Have:** Parse .git/config to resolve did:plc:... from the remote URL. | 18| **Auth** | Stores oauth token; acts as a git-credential-helper. | **Plan:** Store AT Proto session; inject auth headers into git operations if possible, or manage SSH keys via API. | 19| **Output** | TTY \= Tables. Pipe \= Text. \--json \= Structured. | **Plan:** Use is-interactive check. Default to "Human Mode". Force "Machine Mode" via flags. | 20| **Filtering** | \--json name,url (filters fields). | **Plan:** Support basic \--json flag first. Add field filtering (--json "cloneUrl,did") to save LLM context window tokens. | 21| **Extensions** | Allows custom subcommands. | _Out of Scope for V1._ | 22 23## High-Level Architecture (Refined) 24 25The CLI acts as a "Context Engine" before it even hits the API. 26`graph TD` 27`User[User / LLM] -->|Command| CLI` 28 29 `subgraph "Context Engine"` 30 `Git[Local .git/config] -->|Read Remote| Resolver[Context Resolver]` 31 `Resolver -->|Inferred DID| Payload` 32 `end` 33 34 `subgraph "Execution"` 35 `Payload -->|XRPC Request| API[Tangled AppView]` 36 `Payload -->|Git Command| Shell[Git Shell]` 37 `end` 38 39 `API --> Output` 40 `Shell --> Output` 41 42## Tech Stack (TypeScript) 43 44| Component | Library | Purpose | 45| :---------------- | :---------------------- | :--------------------------------------------------------------------------------------------- | 46| **Framework** | **commander** | CLI routing and command parsing (e.g., `tangled repo create`). | 47| **API Client** | **@atproto/api** | Official AT Protocol XRPC client, session management, and record operations. | 48| **Lexicon Tools** | **@atproto/lexicon** | Schema validation for custom Tangled.org lexicons (e.g., `sh.tangled.publicKey`). | 49| **Git Context** | **git-url-parse** | Parses remote URLs to extract the Tangled DID/NSID from `.git/config`. | 50| **Git Ops** | **simple-git** | Wraps local git operations safely. | 51| **Validation** | **zod** | Input validation and schema generation for LLMs. | 52| **Interactivity** | **@inquirer/prompts** | Modern, user-friendly prompts for interactive flows. | 53| **Formatting** | **cli-table3** | Pretty tables for "Human Mode" output (following gh CLI patterns). | 54| **OS Keychain** | **@napi-rs/keyring** | Cross-platform secure storage for AT Protocol session tokens (macOS, Windows, Linux). | 55| **TypeScript** | **tsx** | Fast TypeScript execution for development and testing. | 56 57## Agent Integration (The "LLM Friendly" Layer) 58 59To make this tool accessible to Claude Code/Gemini, we adopt gh's best patterns: 60 61### Rule 1: Context is King 62 63LLMs often hallucinate repo IDs. 64 65- **Design:** If the user/LLM runs tangled issue list inside a folder, **do not** ask for the repo DID. Infer it. 66- **Fallback:** Only error if no git remote is found. 67 68### Rule 2: Precision JSON (--json \<fields\>) 69 70LLMs have token limits. Returning a 50KB repo object is wasteful. 71 72- **Feature:** tangled repo view \--json name,cloneUrl,description 73- **Implementation:** Use lodash/pick to filter the API response before printing to stdout. 74 75### Rule 3: Fail Fast, Fail Loud 76 77LLMs can't read error messages buried in HTML or long stack traces. Provide a `--no-input` flag that forces the CLI to error if it can't resolve context or if required flags are missing. 78 79### Rule 4: Flexible Input for Issue Bodies 80 81Following `gh`'s pattern, `tangled issue create` will support various ways to provide the issue body, making it LLM-friendly and flexible for scripting. It will accept: 82 83- `--body "Text"` or `-b "Text"` for a direct string. 84- `--body-file ./file.md` or `-F ./file.md` to read from a file. 85- `--body-file -` or `-F -` to read from standard input (stdin). 86 87### Summary of Improvements 88 89- **Context Inference:** This is the "killer feature" of gh that we are copying. It makes the tool usable for humans and safer for LLMs (less typing = fewer errors). 90- **Filtered JSON:** Saves tokens for LLM context windows. 91- **Git Config Integration:** Treats the local .git folder as a database of configuration, reducing the need for environment variables or complex flags. 92- **Flexible Issue Body Input:** Improves usability for both humans and LLMs by allowing diverse input methods for issue descriptions. 93 94## Examples Tangled CLI Usage 95 96```bash 97tangled auth login (opens a browser for auth) 98tangled repo create my-new-repo 99cd my-new-repo 100tangled issue create "Bug: Something is broken" --body "Detailed description of the bug here." 101echo "Another bug description from stdin." | tangled issue create "Bug: From stdin" --body-file - 102tangled issue list --json "id,title" 103tangled pr create --base main --head my-feature --title "Add new feature" --body-file ./pr_description.md 104tangled pr view 123 105tangled pr comment 123 --body "Looks good, small change needed." 106``` 107 108## Basic Commands 109 110Basic commands include auth, key management, repo creation, issue management, and pull request management. 111 112`tangled auth login` 113 114- Logs in the user, ideally through a web browser flow for security. 115 `tangled auth logout` 116- Logs out the user, clearing the session. 117 `tangled ssh-key add <public-key-path>` 118- Uploads the provided public SSH key to the user's tangled.org account via the API. 119 `tangled ssh-key verify` 120- Verifies that the user's SSH key is correctly set up and can authenticate with tangled.org. Returns the associated DID and handle if successful. 121 `tangled repo create <repo-name>` 122- Creates a new repository under the user's account. 123 `tangled repo view [--json <fields>]` 124- Displays details about the current repository. If `--json` is provided, outputs only the specified fields in JSON format. 125 `tangled issue create "<title>" [--body "<body>" | --body-file <file> | -F -]` 126- Creates a new issue in the current repository with the given title and optional body, which can be provided via flag, file, or stdin. 127 `tangled pr create --base <base-branch> --head <head-branch> --title <title> [--body <body> | --body-file <file> | -F -]` 128- Creates a new pull request in the current repository from a head branch to a base branch. 129 `tangled pr list [--json <fields>]` 130- Lists pull requests for the current repository. 131 `tangled pr view <id> [--json <fields>]` 132- Displays detailed information about a specific pull request, including comments. 133 `tangled pr comment <id> [--body <body> | --body-file <file> | -F -]` 134- Adds a comment to a pull request. 135 `tangled pr review <id> --comment <comment> [--approve | --request-changes]` 136- Submits a review for a pull request, with optional approval or request for changes. 137 138## Design Decisions & Outstanding Issues 139 140This section documents key design decisions and tracks outstanding architectural questions. 141 142### (Resolved) SSH Key Management (`gh` Compatibility) 143 144- **Original Question:** How does `gh` manage SSH keys, and can we follow that pattern? 145- **Resolution:** Analysis shows that `gh` does _not_ manage private keys. It facilitates uploading the user's _public_ key to their GitHub account. The local SSH agent handles the private key. 146- **Our Approach:** The `tangled ssh-key add` command follows this exact pattern. It provides a user-friendly way to upload a public key to `tangled.org`. This resolves the core of this issue, as it is compatible with external key managers like 1Password's SSH agent. 147 148### (Decided) Secure Session Storage 149 150- **Original Question:** How should we securely store the AT Proto session token? 151- **Resolution:** Storing sensitive tokens in plaintext files is not secure. 152- **Our Approach:** The CLI will use the operating system's native keychain for secure storage (e.g., macOS Keychain, Windows Credential Manager, or Secret Service on Linux). A library like `keytar` will be used to abstract the platform differences. 153 154### (Decided) Configuration Resolution Order 155 156- **Original Question:** How should settings be resolved from different sources? 157- **Resolution:** A clear precedence order is necessary. 158- **Our Approach:** The CLI will resolve settings in the following order of precedence (highest first): 159 1. Command-line flags (e.g., `--repo-did ...`) 160 2. Environment variables (e.g., `TANGLED_REPO_DID=...`) 161 3. Project-specific config file (e.g., `.tangled/config.yml` in the current directory) 162 4. Global user config file (e.g., `~/.config/tangled/config.yml`) 163 164### (Decided for V1) Authentication Flow: App Passwords (PDS) 165 166- **Original Question:** Can we allow auth through a web browser? 167- **Resolution:** For the initial version, the CLI will use **App Passwords** for authentication. This is the standard and simplest method for third-party AT Protocol clients and aligns with existing practices. 168- **`tangled auth login` Flow:** When running `tangled auth login`, the CLI will prompt the user for their **PDS handle** (e.g., `@mark.bsky.social`) and an **App Password**. 169- **Generating an App Password:** Users typically generate App Passwords from their PDS's settings (e.g., in the official Bluesky app under "Settings -> App Passwords", or on their self-hosted PDS web interface). The CLI **does not** generate app passwords. 170- **Session Management:** The session established is with the user's PDS, and this authenticated session is then used to interact with `tangled.org`'s App View/Service. 171- **OAuth Support:** Implementing a web-based OAuth flow (similar to `gh`'s approach) is more complex and not a standard part of the AT Protocol client authentication flow. This approach is deferred for future consideration. 172 173## Future Expansion Opportunities 174 175The analysis of the `tangled.org` API revealed a rich set of features that are not yet part of the initial CLI plan but represent significant opportunities for future expansion. These include: 176 177- **CI/CD Pipelines:** Commands to view pipeline status and manage CI/CD jobs. 178- **Repository Secrets:** A dedicated command set for managing CI/CD secrets within a repository (`tangled repo secret ...`). 179- **Advanced Git Operations:** Commands to interact with the commit log, diffs, branches, and tags directly via the API, augmenting local `git` commands. 180- **Social & Feed Interactions:** Commands for starring repositories, reacting to feed items, and managing the user's social graph (following/unfollowing). 181- **Label Management:** Commands to create, apply, and remove labels from issues and pull requests. 182- **Collaboration:** Commands to manage repository collaborators. 183- **Fork Management:** Commands for forking repositories and managing the sync status of forks. 184- **Reactions**: Commands to add and remove reactions on issues, pull requests, and comments. 185- **Commenting on Issues**: Commands to add comments to issues. 186 187## Task Management 188 189We're bootstrapping task tracking with TODO.md, but will migrate all tasks into Tangled issues and dog food the product as soon as we have basic issue creation and listing working. 190 191## Development 192 193### Prerequisites 194 195- Node.js 22.0.0 or higher (latest LTS) 196- npm (comes with Node.js) 197 198### Installation 199 200Clone the repository and install dependencies: 201 202```bash 203npm install 204``` 205 206### Available Scripts 207 208- `npm run dev` - Run the CLI in development mode (with hot reload via tsx) 209- `npm run build` - Build TypeScript to JavaScript (output to `dist/`) 210- `npm test` - Run tests once 211- `npm run test:watch` - Run tests in watch mode 212- `npm run test:coverage` - Run tests with coverage report 213- `npm run lint` - Check code with Biome linter 214- `npm run lint:fix` - Auto-fix linting issues 215- `npm run format` - Format code with Biome 216- `npm run typecheck` - Type check without building 217 218### Running Locally 219 220```bash 221# Run the CLI in development mode 222npm run dev -- --version 223npm run dev -- --help 224 225# Build and run the production version 226npm run build 227node dist/index.js --version 228 229# Install globally for local testing 230npm link 231tangled --version 232tangled --help 233npm unlink -g tangled-cli # Unlink when done 234``` 235 236### Project Structure 237 238``` 239tangled-cli/ 240├── src/ 241│ ├── index.ts # Main CLI entry point 242│ ├── commands/ # Command implementations 243│ ├── lib/ # Core business logic 244│ └── utils/ # Helper functions 245├── tests/ # Test files 246├── dist/ # Build output (gitignored) 247└── package.json # Package configuration 248``` 249 250### Coding Guidelines 251 252**IMPORTANT: These guidelines must be followed for all code contributions.** 253 254#### Validation Functions Location 255 256**ALL validation logic belongs in `src/utils/validation.ts`** 257 258- Use Zod schemas for all input validation 259- Boolean validation helpers (e.g., `isValidHandle()`, `isValidTangledDid()`) go in `validation.ts` 260- Never define validation functions in other files - import from `validation.ts` 261- Validation functions should return `true/false` or use Zod's `safeParse()` pattern 262 263Example: 264```typescript 265// ✅ CORRECT: validation.ts 266export function isValidHandle(handle: string): boolean { 267 return handleSchema.safeParse(handle).success; 268} 269 270// ❌ WRONG: Don't define validators in other files 271// git.ts should import isValidHandle, not define it 272``` 273 274#### Test Coverage Requirements 275 276**ALL code must have comprehensive test coverage** 277 278- Every new feature requires tests in the corresponding `tests/` directory 279- Commands must have test files (e.g., `src/commands/foo.ts``tests/commands/foo.test.ts`) 280- Utilities must have test files (e.g., `src/utils/bar.ts``tests/utils/bar.test.ts`) 281- Tests should cover: 282 - Success cases (happy path) 283 - Error cases (validation failures, network errors, etc.) 284 - Edge cases (empty input, boundary values, etc.) 285- Aim for high test coverage - tests are not optional 286 287Example test structure: 288```typescript 289describe('MyFeature', () => { 290 describe('successfulOperation', () => { 291 it('should handle valid input', async () => { /* ... */ }); 292 it('should handle edge case', async () => { /* ... */ }); 293 }); 294 295 describe('errorHandling', () => { 296 it('should reject invalid input', async () => { /* ... */ }); 297 it('should handle network errors', async () => { /* ... */ }); 298 }); 299}); 300``` 301 302#### Pull Request Checklist 303 304Before submitting code, verify: 305- [ ] All validation functions are in `validation.ts` 306- [ ] Comprehensive tests are written and passing 307- [ ] TypeScript compilation passes (`npm run typecheck`) 308- [ ] Linting passes (`npm run lint`) 309- [ ] All tests pass (`npm test`) 310 311### Technology Stack 312 313- **TypeScript 5.7.2** - Latest stable with strict mode enabled 314- **Node.js 22+** - Latest LTS target 315- **ES2023** - Latest stable ECMAScript target 316- **Biome** - Fast linter and formatter (replaces ESLint + Prettier) 317- **Vitest** - Fast unit test framework 318- **Commander.js** - CLI framework 319- **tsx** - Fast TypeScript execution for development