Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
118 changes: 118 additions & 0 deletions openspec/changes/archive/2026-01-10-add-list-spaceline/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Spaceline Output Format Design

## Context

The `openspec list` command currently outputs simple tabular data. Users (particularly AI assistants) need a more compact, information-dense format that shows:
- Visual progress indicators
- Git change statistics

This format is inspired by "spaceline" prompts used in AI coding workflows.

## Goals / Non-Goals

**Goals:**
- Compact, visually rich output format for change listings
- Git statistics integration (files added/removed)
- Graceful degradation when data is unavailable

**Non-Goals:**
- Complex Git history analysis (simple diff stats only)
- Persistent configuration for spaceline format

## Decisions

### Decision 1: Git stats via `git diff --numstat`

**What:** Use `git diff --numstat` to count file additions/removals.

**Why:**
- Simple, reliable command available in all Git installations
- Machine-readable output format
- No additional dependencies

**Format interpretation:**
```
123 45 path/to/file.ts # 123 additions, 45 deletions β†’ counts as "added" (↑)
10 50 another/file.ts # 10 additions, 50 deletions β†’ counts as "removed" (↓)
```

### Decision 2: Emoji constants in separate module

**What:** Create `src/utils/spaceline-formatter.ts` with emoji constants.

**Why:**
- Centralized emoji management
- Easy to update/disable if needed
- Testable in isolation

**Emojis used:**
- `πŸ“` - Change icon
- `󱃖` - Progress (Nerd Font icon, fallback to `β–‘`)
- `σ°·«` - Implementation status
- `✎` - Delta count
- `πŸ“‹` - Open items
- `󰘬` - Git branch

### Decision 3: Spaceline mutually exclusive with JSON

**What:** `--spaceline` and `--json` flags cannot be used together.

**Why:**
- Spaceline is a human-readable format
- JSON is for machine parsing
- Mixing them doesn't make sense

**Behavior:** Exit with error code 2 and clear message.

## Risks / Trade-offs

### Risk: Emoji/Nerd Font rendering

**Issue:** Some terminals don't support Nerd Font icons (󱃖, σ°·«, 󰘬).

**Mitigation:**
- Use standard emoji fallbacks where possible
- Consider `--no-emoji` flag in future if needed
- Terminal font issues are user's responsibility

### Risk: Git command availability

**Issue:** `git diff` may fail if not in a Git repo or Git not installed.

**Mitigation:**
- Wrap in try-catch, show `(?)` on failure
- Don't fail the entire command
- Document this behavior

### Risk: Performance with many changes

**Issue:** Computing Git stats for each change could be slow.

**Mitigation:**
- Only run Git commands when `--spaceline` is used
- Consider caching in future if needed
- Expected usage is small number of active changes (<20)

## Implementation Structure

```
src/utils/
β”œβ”€β”€ git-stats.ts # Git diff statistics
└── spaceline-formatter.ts # Format assembly

src/core/list.ts # Add spaceline mode
src/cli/index.ts # Add --spaceline flag
```

## Migration Plan

No migration needed - this is a new feature flag.

## Open Questions

1. **Git base:** What should we diff against? Main branch? HEAD?
- **Answer:** Diff against `main` or `origin/main` if available, otherwise `HEAD~1`
- **Implementation detail:** Use `git diff --numstat main` or similar

2. **Category detection:** How to map change ID to category (e.g., "add" β†’ "Implementation")?
- **Answer:** Simple prefix mapping: `add-*` β†’ Implementation, `update-*` β†’ Refactor, `remove-*` β†’ Deprecation
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Add Spaceline Output Format to List Command

## Why

Developers need a visually compact, information-dense way to view active changes with key metrics at a glance. The current `openspec list` output shows basic information but lacks:
1. Visual progress indicators
2. Git change statistics

This is particularly useful for AI coding assistants that need to quickly assess project state during development sessions.

## What Changes

- Add `--spaceline` flag to `openspec list` command
- Display changes in a compact, emoji-rich horizontal format:
- Change ID and title
- Visual progress bar with percentage
- Task completion status
- Git diff statistics (files added/modified)
- Sort output by change ID (alphabetical)

Example output:
```
πŸ“ add-api-versioning | 󱃖 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘ 92.5%
σ°·« Implementation (4/7) | ✎ 12 | πŸ“‹ 5 open | 󰘬 feature/add-api-versioning (↑5 ↓2)
```

## Impact

- Affected specs: `cli-list`
- Affected code:
- `src/core/list.ts` - Add spaceline format output
- `src/cli/index.ts` - Add `--spaceline` option
- New utility modules for Git statistics and spaceline formatting
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
## ADDED Requirements

### Requirement: Spaceline Output Format

The command SHALL support a `--spaceline` flag that displays changes in a compact, visually rich horizontal format with emoji indicators and progress metrics.

#### Scenario: Spaceline basic format

- **WHEN** `openspec list --spaceline` is executed
- **THEN** display each change in a multi-line format:
- Line 1: Change icon, ID, and progress bar with percentage
- Line 2: Task status, delta count, open items, and branch with Git stats
- **AND** sort changes alphabetically by ID

#### Scenario: Spaceline with all elements

- **WHEN** a change has all available information
- **THEN** display:
```
πŸ“ {change-id} | {progress-bar} {percentage}%
{status-icon} {category} ({completed}/{total} tasks) | {delta-icon} {count} | {open-icon} {open} | {branch-icon} {branch} ({added}↑ {removed}↓)
```
- **WHERE**:
- `progress-bar` is a 10-character visual bar using `β–ˆ` and `β–‘`
- `percentage` is task completion percentage
- `status-icon` is implementation stage emoji (σ°·« for implementation, etc.)
- `category` is derived from change ID prefix (e.g., "add" β†’ "Implementation")
- `delta-icon` `✎` shows spec delta count
- `open-icon` `πŸ“‹` shows open TODO/pr items count
- `branch-icon` `󰘬` shows current Git branch
- `added↑` shows number of files with net additions
- `removed↓` shows number of files with net removals

Comment on lines +15 to +33
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Spec example output doesn’t match the implemented spaceline line format (status icon + git stats ordering).

The formatter output (and PR example) includes the status icon on Line 1 and uses ↑{added} ↓{removed} ordering; the spec example currently differs. Also, add a language to the fenced block (MD040).

Proposed spec fix
 #### Scenario: Spaceline with all elements

 - **WHEN** a change has all available information
 - **THEN** display:
-  ```
-  πŸ“ {change-id} | {progress-bar} {percentage}%
-  {status-icon} {category} ({completed}/{total} tasks) | {delta-icon} {count} | {open-icon} {open} | {branch-icon} {branch} ({added}↑ {removed}↓)
-  ```
+  ```text
+  πŸ“ {change-id} | {status-icon} {progress-bar} {percentage}%
+  {status-icon} {category} ({completed}/{total}) | {delta-icon} {count} | {open-icon} {open} open | {branch-icon} {branch} (↑{added} ↓{removed})
+  ```
 - **WHERE**:
   - `progress-bar` is a 10-character visual bar using `β–ˆ` and `β–‘`
   - `percentage` is task completion percentage
   - `status-icon` is implementation stage emoji (σ°·« for implementation, etc.)
   - `category` is derived from change ID prefix (e.g., "add" β†’ "Implementation")
   - `delta-icon` `✎` shows spec delta count
   - `open-icon` `πŸ“‹` shows open TODO/pr items count
   - `branch-icon` `󰘬` shows current Git branch
-  - `added↑` shows number of files with net additions
-  - `removed↓` shows number of files with net removals
+  - `↑{added}` shows number of files with net additions
+  - `↓{removed}` shows number of files with net removals

Also applies to: 34-40

πŸ€– Prompt for AI Agents
In
@openspec/changes/archive/2026-01-10-add-list-spaceline/specs/cli-list/spec.md
around lines 15 - 33, The spec example block is inconsistent with the
implemented spaceline: move {status-icon} to Line 1 before {progress-bar} and
match git stat ordering to (↑{added} ↓{removed}); also add a language tag to the
fenced block (use "text") and adjust the second line to mirror the formatter:
"πŸ“ {change-id} | {status-icon} {progress-bar} {percentage}%" and "{status-icon}
{category} ({completed}/{total}) | {delta-icon} {count} | {open-icon} {open}
open | {branch-icon} {branch} (↑{added} ↓{removed})", updating the WHERE list
entries for ↑{added} and ↓{removed} accordingly.

#### Scenario: Spaceline with minimal data

- **WHEN** Git stats cannot be computed
- **THEN** display placeholder values:
- Git stats: omitted or `(?)`
- Branch: current branch or `(no branch)`

### Requirement: Git Statistics

The command SHALL compute file change statistics from the Git repository when in spaceline mode.

#### Scenario: Computing Git diff statistics

- **WHEN** computing Git statistics for a change
- **THEN** run `git diff --numstat` against the relevant branch or base
- **AND** count files where additions > deletions as `added` (↑)
- **AND** count files where deletions > additions as `removed` (↓)
- **AND** handle non-Git directories gracefully by showing `(?)`

#### Scenario: Git statistics errors

- **WHEN** Git commands fail or repo is unavailable
- **THEN** display `(?)` instead of statistics
- **AND** do not fail the entire list command

### Requirement: Spaceline Flag Compatibility

The `--spaceline` flag SHALL be mutually exclusive with `--json` and take precedence over `--long`.

#### Scenario: Spaceline overrides long format

- **WHEN** both `--spaceline` and `--long` are provided
- **THEN** use spaceline format
- **AND** ignore `--long` flag

#### Scenario: Spaceline conflicts with JSON

- **WHEN** both `--spaceline` and `--json` are provided
- **THEN** display error: "Cannot use --spaceline with --json"
- **AND** exit with code 2

## MODIFIED Requirements

### Requirement: Flags

The command SHALL accept flags to select the noun being listed and output format.

#### Scenario: Selecting specs
- **WHEN** `--specs` is provided
- **THEN** list specs instead of changes

#### Scenario: Selecting changes
- **WHEN** `--changes` is provided
- **THEN** list changes explicitly (same as default behavior)

#### Scenario: Spaceline output format
- **WHEN** `--spaceline` is provided
- **THEN** display changes in compact spaceline format with emoji indicators
- **AND** include progress bars, task status, and Git stats
47 changes: 47 additions & 0 deletions openspec/changes/archive/2026-01-10-add-list-spaceline/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## 1. Implementation

- [x] 1.1 Create `src/utils/git-stats.ts` module for Git statistics
- [x] 1.1.1 Implement `getGitDiffStats()` function using `git diff --numstat`
- [x] 1.1.2 Add error handling for non-Git directories
- [x] 1.1.3 Return `{ added: number, removed: number }` or `null`

- [x] 1.2 Create `src/utils/spaceline-formatter.ts` for output formatting
- [x] 1.2.1 Implement `generateProgressBar(percentage: number): string`
- [x] 1.2.2 Implement `formatSpaceline(change: ChangeData, stats: SpacelineStats): string[]`
- [x] 1.2.3 Add emoji constants for all UI elements

- [x] 1.3 Update `src/core/list.ts`
- [x] 1.3.1 Add `spaceline` option to `execute()` method signature
- [x] 1.3.2 Implement `executeSpaceline()` method for spaceline output
- [x] 1.3.3 Integrate Git stats collection

- [x] 1.4 Update `src/cli/index.ts`
- [x] 1.4.1 Add `--spaceline` option to list command
- [x] 1.4.2 Add mutual exclusion check with `--json`
- [x] 1.4.3 Pass spaceline flag to ListCommand

## 2. Testing

- [x] 2.1 Create `test/utils/git-stats.test.ts`
- [x] 2.1.1 Test successful Git stats parsing
- [x] 2.1.2 Test non-Git directory handling
- [x] 2.1.3 Test error scenarios

- [x] 2.2 Create `test/utils/spaceline-formatter.test.ts`
- [x] 2.2.1 Test progress bar generation at various percentages
- [x] 2.2.2 Test full spaceline format output
- [x] 2.2.3 Test minimal data fallbacks

- [x] 2.3 Update `test/core/list.test.ts`
- [x] 2.3.1 Existing tests still pass
- [x] 2.3.2 No breaking changes to existing functionality

- [x] 2.4 Manual testing with `pnpm link`
- [x] 2.4.1 Verified spaceline output in real project
- [x] 2.4.2 Tested with Git repository

## 3. Documentation

- [x] 3.1 Update `openspec/specs/cli-list/spec.md` (done via delta)
- [x] 3.2 Update help text in `src/cli/index.ts` (added --spaceline option description)
- [ ] 3.3 Add example output to README if needed (deferred - can be added later)
53 changes: 45 additions & 8 deletions openspec/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,51 @@ A minimal CLI tool that helps developers set up OpenSpec file structures and kee
- Package Manager: pnpm
- CLI Framework: Commander.js
- User Interaction: @inquirer/prompts
- Validation: Zod
- Terminal UI: Chalk, Ora
- File Operations: fast-glob
- YAML Parsing: yaml
- Distribution: npm package
- Testing: Vitest
- Versioning: @changesets/cli

## Project Structure
```
src/
β”œβ”€β”€ cli/ # CLI command implementations
β”œβ”€β”€ core/ # Core OpenSpec logic (templates, structure)
└── utils/ # Shared utilities (file operations, rollback)
β”œβ”€β”€ commands/ # CLI command handlers
β”‚ β”œβ”€β”€ change.ts # Change proposal commands
β”‚ β”œβ”€β”€ spec.ts # Spec management commands
β”‚ β”œβ”€β”€ completion.ts # Shell completion commands
β”‚ β”œβ”€β”€ config.ts # Configuration commands
β”‚ β”œβ”€β”€ validate.ts # Validation commands
β”‚ └── show.ts # Display commands
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ configurators/ # AI tool configuration
β”‚ β”‚ β”œβ”€β”€ registry.ts
β”‚ β”‚ β”œβ”€β”€ [agent].ts
β”‚ β”‚ └── slash/ # Slash command configurators
β”‚ β”œβ”€β”€ completions/ # Shell completion system
β”‚ β”‚ β”œβ”€β”€ generators/ # Bash, Zsh, Fish, PowerShell
β”‚ β”‚ β”œβ”€β”€ installers/
β”‚ β”‚ └── templates/
β”‚ β”œβ”€β”€ artifact-graph/ # Artifact dependency resolution
β”‚ β”œβ”€β”€ templates/ # AI instruction templates
β”‚ β”œβ”€β”€ schemas/ # OpenSpec schema definitions
β”‚ β”œβ”€β”€ parsers/ # Markdown/change parsers
β”‚ └── validation/ # Spec validation logic
└── utils/ # Shared utilities

dist/ # Compiled output (gitignored)
```
Comment on lines 19 to 46
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟑 Minor

Add a language tag to the fenced project-structure block (MD040).

Proposed markdownlint fix
 ## Project Structure
-```
+```text
 src/
 β”œβ”€β”€ commands/           # CLI command handlers
 β”‚   β”œβ”€β”€ change.ts      # Change proposal commands
 β”‚   β”œβ”€β”€ spec.ts        # Spec management commands
 β”‚   β”œβ”€β”€ completion.ts  # Shell completion commands
 β”‚   β”œβ”€β”€ config.ts      # Configuration commands
 β”‚   β”œβ”€β”€ validate.ts    # Validation commands
 β”‚   └── show.ts        # Display commands
 β”œβ”€β”€ core/
 β”‚   β”œβ”€β”€ configurators/  # AI tool configuration
 β”‚   β”‚   β”œβ”€β”€ registry.ts
 β”‚   β”‚   β”œβ”€β”€ [agent].ts
 β”‚   β”‚   └── slash/      # Slash command configurators
 β”‚   β”œβ”€β”€ completions/    # Shell completion system
 β”‚   β”‚   β”œβ”€β”€ generators/ # Bash, Zsh, Fish, PowerShell
 β”‚   β”‚   β”œβ”€β”€ installers/
 β”‚   β”‚   └── templates/
 β”‚   β”œβ”€β”€ artifact-graph/ # Artifact dependency resolution
 β”‚   β”œβ”€β”€ templates/      # AI instruction templates
 β”‚   β”œβ”€β”€ schemas/        # OpenSpec schema definitions
 β”‚   β”œβ”€β”€ parsers/        # Markdown/change parsers
 β”‚   └── validation/     # Spec validation logic
 └── utils/              # Shared utilities

 dist/           # Compiled output (gitignored)
</details>

<details>
<summary>🧰 Tools</summary>

<details>
<summary>πŸͺ› markdownlint-cli2 (0.18.1)</summary>

20-20: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>

</details>

<details>
<summary>πŸ€– Prompt for AI Agents</summary>

In @openspec/project.md around lines 19 - 46, The fenced code block under the
"## Project Structure" section is missing a language tag (MD040); update the
opening fence from totext so the tree block is explicitly tagged (i.e.,
replace the triple backticks before the src/ tree with ```text) to satisfy the
markdownlint rule.


</details>

<!-- This is an auto-generated comment by CodeRabbit -->


## Conventions
- TypeScript strict mode enabled
- ES2022 target, NodeNext module resolution
- Async/await for all asynchronous operations
- Minimal dependencies principle
- Clear separation of CLI, core logic, and utilities
- ESLint with typescript-eslint
- File naming: kebab-case for directories, PascalCase for types
- AI-friendly code with descriptive names

## Error Handling
Expand All @@ -37,17 +65,26 @@ dist/ # Compiled output (gitignored)
- Use console methods directly (no logging library)
- console.log() for normal output
- console.error() for errors (outputs to stderr)
- Use chalk for colored output
- Use ora for spinners/loading indicators
- No verbose/debug modes initially (keep it simple)

## Testing Strategy
- Manual testing via `pnpm link` during development
- Smoke tests for critical paths only (init, help commands)
- No unit tests initially - add when complexity grows
- Test commands: `pnpm test:smoke` (when added)
- Framework: Vitest with globals enabled
- Test files: `test/**/*.test.ts`
- Environment: node (default)
- Coverage: text, json, html reporters
- Run tests: `pnpm test`
- Watch mode: `pnpm test:watch`
- Coverage report: `pnpm test:coverage`
- Test timeout: 10s (configurable)

## Development Workflow
- Use pnpm for all package management
- Run `pnpm run build` to compile TypeScript
- Run `pnpm run dev` for development mode
- Test locally with `pnpm link`
- Follow OpenSpec's own change-driven development process
- Follow OpenSpec's own change-driven development process
- Use changesets for versioning: `pnpm changeset`
- Release: `pnpm run release` (CI) or `pnpm run release:local`
- Postinstall script ensures permissions
Loading