mirror of
https://github.com/Fission-AI/OpenSpec.git
synced 2026-10-17 05:49:35 +08:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
780acb0ec0 |
@@ -0,0 +1,39 @@
|
||||
## Why
|
||||
|
||||
Users need a way to view and modify their global OpenSpec settings without manually editing JSON files. The `add-global-config-dir` change provides the foundation, but there's no user-facing interface to interact with the config. A dedicated `openspec config` command provides discoverability and ease of use.
|
||||
|
||||
## What Changes
|
||||
|
||||
Add `openspec config` subcommand with the following operations:
|
||||
|
||||
```bash
|
||||
openspec config path # Show config file location
|
||||
openspec config list # Show all current settings
|
||||
openspec config get <key> # Get a specific value
|
||||
openspec config set <key> <value> # Set a value
|
||||
openspec config reset [key] # Reset to defaults (all or specific key)
|
||||
```
|
||||
|
||||
**Example usage:**
|
||||
```bash
|
||||
$ openspec config path
|
||||
/Users/me/.config/openspec/config.json
|
||||
|
||||
$ openspec config list
|
||||
enableTelemetry: true
|
||||
featureFlags: {}
|
||||
|
||||
$ openspec config set enableTelemetry false
|
||||
Set enableTelemetry = false
|
||||
|
||||
$ openspec config get enableTelemetry
|
||||
false
|
||||
```
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: New `cli-config` capability
|
||||
- Affected code:
|
||||
- New `src/commands/config.ts`
|
||||
- Update CLI entry point to register config command
|
||||
- Dependencies: Requires `add-global-config-dir` to be implemented first
|
||||
@@ -0,0 +1,105 @@
|
||||
## Context
|
||||
|
||||
OpenSpec needs a standard location for user-level configuration that works across platforms and follows established conventions. This will serve as the foundation for settings, feature flags, and future artifacts like workflows or templates.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Provide a single, well-defined location for global config
|
||||
- Follow XDG Base Directory Specification (widely adopted by CLI tools)
|
||||
- Support cross-platform usage (Unix, macOS, Windows)
|
||||
- Keep implementation minimal - just the foundation
|
||||
- Enable future expansion (cache, state, workflows)
|
||||
|
||||
**Non-Goals:**
|
||||
- Project-local config override (not in scope)
|
||||
- Config file migration tooling
|
||||
- Config validation CLI commands
|
||||
- Multiple config profiles
|
||||
|
||||
## Decisions
|
||||
|
||||
### Path Resolution Strategy
|
||||
|
||||
**Decision:** Use XDG Base Directory Specification with platform fallbacks.
|
||||
|
||||
```
|
||||
Unix/macOS: $XDG_CONFIG_HOME/openspec/ or ~/.config/openspec/
|
||||
Windows: %APPDATA%/openspec/
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- XDG is the de facto standard for CLI tools (used by gh, bat, ripgrep, etc.)
|
||||
- Environment variable override allows user customization
|
||||
- Windows uses its native convention (%APPDATA%) for better integration
|
||||
|
||||
**Alternatives considered:**
|
||||
- `~/.openspec/` - Simple but clutters home directory
|
||||
- `~/Library/Application Support/` on macOS - Overkill for a CLI tool
|
||||
|
||||
### Config File Format
|
||||
|
||||
**Decision:** JSON (`config.json`)
|
||||
|
||||
**Rationale:**
|
||||
- Native Node.js support (no dependencies)
|
||||
- Human-readable and editable
|
||||
- Type-safe with TypeScript
|
||||
- Matches project.md's "minimal dependencies" principle
|
||||
|
||||
**Alternatives considered:**
|
||||
- YAML - Requires dependency, more error-prone to edit
|
||||
- TOML - Less common in Node.js ecosystem
|
||||
- Environment variables only - Too limited for structured settings
|
||||
|
||||
### Config Schema
|
||||
|
||||
**Decision:** Flat structure with typed fields, start minimal.
|
||||
|
||||
```typescript
|
||||
interface GlobalConfig {
|
||||
featureFlags?: Record<string, boolean>;
|
||||
}
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- `featureFlags` enables controlled rollout of new features
|
||||
- Optional fields with defaults avoid breaking changes
|
||||
- Flat structure is easy to understand and extend
|
||||
|
||||
### Loading Strategy
|
||||
|
||||
**Decision:** Read from disk on each call, no caching.
|
||||
|
||||
```typescript
|
||||
export function getGlobalConfig(): GlobalConfig {
|
||||
return loadConfigFromDisk();
|
||||
}
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
- CLI commands are short-lived; caching adds complexity without benefit
|
||||
- Reading a small JSON file is ~1ms; negligible overhead
|
||||
- Always returns fresh data; no cache invalidation concerns
|
||||
- Simpler implementation
|
||||
|
||||
### Directory Creation
|
||||
|
||||
**Decision:** Create directory only when saving, not when reading.
|
||||
|
||||
**Rationale:**
|
||||
- Don't create empty directories on read operations
|
||||
- Users who never save config won't have unnecessary directories
|
||||
- Aligns with principle of least surprise
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| Config file corruption | Return defaults on parse error, log warning |
|
||||
| Permissions issues | Check write permissions before save, clear error message |
|
||||
| Future schema changes | Use optional fields, add version field if needed later |
|
||||
|
||||
## Open Questions
|
||||
|
||||
None - this proposal is intentionally minimal.
|
||||
@@ -0,0 +1,20 @@
|
||||
## Why
|
||||
|
||||
OpenSpec currently has no mechanism for user-level global settings or feature flags. As the CLI grows, we need a standard location to store user preferences, experimental features, and other configuration that persists across projects. Following XDG Base Directory Specification provides a well-understood, cross-platform approach.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add new `src/core/global-config.ts` module with:
|
||||
- Path resolution following XDG Base Directory spec (`$XDG_CONFIG_HOME/openspec/` or fallback)
|
||||
- Cross-platform support (Unix, macOS, Windows)
|
||||
- Lazy config loading with sensible defaults
|
||||
- TypeScript types for config shape
|
||||
- Export a global config directory path getter for future use (workflows, templates, cache)
|
||||
- Initial config schema supports 1-2 settings/feature flags only
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs: New `global-config` capability (no existing specs modified)
|
||||
- Affected code:
|
||||
- New `src/core/global-config.ts`
|
||||
- Update `src/core/index.ts` to export new module
|
||||
@@ -0,0 +1,76 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Global Config Directory Path
|
||||
|
||||
The system SHALL resolve the global configuration directory path following XDG Base Directory Specification with platform-specific fallbacks.
|
||||
|
||||
#### Scenario: Unix/macOS with XDG_CONFIG_HOME set
|
||||
- **WHEN** `$XDG_CONFIG_HOME` environment variable is set to `/custom/config`
|
||||
- **THEN** `getGlobalConfigDir()` returns `/custom/config/openspec`
|
||||
|
||||
#### Scenario: Unix/macOS without XDG_CONFIG_HOME
|
||||
- **WHEN** `$XDG_CONFIG_HOME` environment variable is not set
|
||||
- **AND** the platform is Unix or macOS
|
||||
- **THEN** `getGlobalConfigDir()` returns `~/.config/openspec` (expanded to absolute path)
|
||||
|
||||
#### Scenario: Windows platform
|
||||
- **WHEN** the platform is Windows
|
||||
- **AND** `%APPDATA%` is set to `C:\Users\User\AppData\Roaming`
|
||||
- **THEN** `getGlobalConfigDir()` returns `C:\Users\User\AppData\Roaming\openspec`
|
||||
|
||||
### Requirement: Global Config Loading
|
||||
|
||||
The system SHALL load global configuration from the config directory with sensible defaults when the config file does not exist or cannot be parsed.
|
||||
|
||||
#### Scenario: Config file exists and is valid
|
||||
- **WHEN** `config.json` exists in the global config directory
|
||||
- **AND** the file contains valid JSON matching the config schema
|
||||
- **THEN** `getGlobalConfig()` returns the parsed configuration
|
||||
|
||||
#### Scenario: Config file does not exist
|
||||
- **WHEN** `config.json` does not exist in the global config directory
|
||||
- **THEN** `getGlobalConfig()` returns the default configuration
|
||||
- **AND** no directory or file is created
|
||||
|
||||
#### Scenario: Config file is invalid JSON
|
||||
- **WHEN** `config.json` exists but contains invalid JSON
|
||||
- **THEN** `getGlobalConfig()` returns the default configuration
|
||||
- **AND** a warning is logged to stderr
|
||||
|
||||
### Requirement: Global Config Saving
|
||||
|
||||
The system SHALL save global configuration to the config directory, creating the directory if it does not exist.
|
||||
|
||||
#### Scenario: Save config to new directory
|
||||
- **WHEN** `saveGlobalConfig(config)` is called
|
||||
- **AND** the global config directory does not exist
|
||||
- **THEN** the directory is created
|
||||
- **AND** `config.json` is written with the provided configuration
|
||||
|
||||
#### Scenario: Save config to existing directory
|
||||
- **WHEN** `saveGlobalConfig(config)` is called
|
||||
- **AND** the global config directory already exists
|
||||
- **THEN** `config.json` is written (overwriting if exists)
|
||||
|
||||
### Requirement: Default Configuration
|
||||
|
||||
The system SHALL provide a default configuration that is used when no config file exists.
|
||||
|
||||
#### Scenario: Default config structure
|
||||
- **WHEN** no config file exists
|
||||
- **THEN** the default configuration includes an empty `featureFlags` object
|
||||
|
||||
### Requirement: Config Schema Evolution
|
||||
|
||||
The system SHALL merge loaded configuration with default values to ensure new config fields are available even when loading older config files.
|
||||
|
||||
#### Scenario: Config file missing new fields
|
||||
- **WHEN** `config.json` exists with `{ "featureFlags": {} }`
|
||||
- **AND** the current schema includes a new field `defaultAiTool`
|
||||
- **THEN** `getGlobalConfig()` returns `{ featureFlags: {}, defaultAiTool: <default> }`
|
||||
- **AND** the loaded values take precedence over defaults for fields that exist in both
|
||||
|
||||
#### Scenario: Config file has extra unknown fields
|
||||
- **WHEN** `config.json` contains fields not in the current schema
|
||||
- **THEN** the unknown fields are preserved in the returned configuration
|
||||
- **AND** no error or warning is raised
|
||||
@@ -0,0 +1,25 @@
|
||||
## 1. Core Implementation
|
||||
|
||||
- [ ] 1.1 Create `src/core/global-config.ts` with path resolution
|
||||
- Implement `getGlobalConfigDir()` following XDG spec
|
||||
- Support `$XDG_CONFIG_HOME` environment variable override
|
||||
- Platform-specific fallbacks (Unix: `~/.config/`, Windows: `%APPDATA%`)
|
||||
- [ ] 1.2 Define TypeScript interfaces for config shape
|
||||
- `GlobalConfig` interface with optional fields
|
||||
- Start minimal: just `featureFlags?: Record<string, boolean>`
|
||||
- [ ] 1.3 Implement config loading with defaults
|
||||
- `getGlobalConfig()` - reads config.json if exists, merges with defaults
|
||||
- No directory/file creation on read (lazy initialization)
|
||||
- [ ] 1.4 Implement config saving
|
||||
- `saveGlobalConfig(config)` - writes config.json, creates directory if needed
|
||||
|
||||
## 2. Integration
|
||||
|
||||
- [ ] 2.1 Export new module from `src/core/index.ts`
|
||||
- [ ] 2.2 Add constants for config file name and directory name
|
||||
|
||||
## 3. Testing
|
||||
|
||||
- [ ] 3.1 Manual testing of path resolution on current platform
|
||||
- [ ] 3.2 Test with/without `$XDG_CONFIG_HOME` set
|
||||
- [ ] 3.3 Test config load when file doesn't exist (should return defaults)
|
||||
Reference in New Issue
Block a user