-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat(cli): add openspec config command for global configuration management #382
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ement Implements the `openspec config` command with subcommands: - `path`: Show config file location - `list [--json]`: Show all current settings - `get <key>`: Get a specific value (raw output for scripting) - `set <key> <value> [--string]`: Set a value with auto type coercion - `unset <key>`: Remove a key (revert to default) - `reset --all [-y]`: Reset configuration to defaults - `edit`: Open config in $EDITOR/$VISUAL Key features: - Dot notation for nested key access (e.g., featureFlags.someFlag) - Auto type coercion (true/false → boolean, numbers → number) - --string flag to force string storage - Zod schema validation with unknown field passthrough - Reserved --scope flag for future project-local config - Windows-compatible editor spawning with proper path quoting - Shell completion registry integration
WalkthroughAdds a new "config" CLI command with subcommands (path, list, get, set, unset, reset, edit), a Zod-backed global config schema and utilities, CLI wiring and completion registry entries, tests for command behavior and schema utilities, and design/spec documentation for the feature. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- Add tests for unknown fields with various types - Add test to verify error message path for featureFlags - Add test for number values rejection in featureFlags - Add config set simulation tests to verify full coerce → set → validate flow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (4)
openspec/changes/add-config-command/specs/cli-config/spec.md (1)
1-6: Minor style improvement: Remove redundant "interface" after "CLI".The static analysis tool correctly identified that "CLI interface" is redundant since CLI already stands for "Command Line Interface." Consider simplifying to "CLI" or "command-line interface."
🔎 Suggested fix
-Provide a CLI interface for viewing and modifying global OpenSpec configuration. Enables users to manage settings without manually editing JSON files, with support for scripting and automation. +Provide a CLI for viewing and modifying global OpenSpec configuration. Enables users to manage settings without manually editing JSON files, with support for scripting and automation.src/core/config-schema.ts (2)
186-198: Minor: Redundant type assertion after instanceof check.Line 192 casts
errortoz.ZodErrorright after theinstanceof z.ZodErrorcheck, which is unnecessary since TypeScript already narrows the type. This is harmless but slightly redundant.🔎 Simplified version
} catch (error) { if (error instanceof z.ZodError) { - const zodError = error as z.ZodError; - const messages = zodError.issues.map((e) => `${e.path.join('.')}: ${e.message}`); + const messages = error.issues.map((e) => `${e.path.join('.')}: ${e.message}`); return { success: false, error: messages.join('; ') }; }
57-71: Add guard for empty path edge case insetNestedValue.If
pathis an empty string,path.split('.')returns[""], which would setobj[""] = value. While unlikely in normal CLI usage (since theset <key>command requires an argument), adding a guard likeif (!path) throw new Error('path cannot be empty')would improve robustness.openspec/changes/add-config-command/design.md (1)
1-88: LGTM - Comprehensive design document.The design document appropriately covers the context, goals, decisions, and trade-offs for the new config command. The decision rationale is clear, and the known limitations (dot notation conflicts, type coercion edge cases) are properly documented.
Minor markdown style improvements
The static analysis tools flagged a couple of style issues:
- Line 3: "CLI interface" is redundant (CLI stands for Command Line Interface). Consider simplifying to "CLI".
- Line 46: Add blank lines before and after the table for better markdown formatting.
-The `global-config` spec defines how OpenSpec reads/writes `config.json`, but users currently must edit it by hand. This command provides a CLI interface to that config. +The `global-config` spec defines how OpenSpec reads/writes `config.json`, but users currently must edit it by hand. This command provides a CLI to that config.- Explicit override for edge cases (storing literal string "true") - Follows npm/yarn config patterns **Coercion rules:** + | Input | Stored As | |-------|-----------| | `true`, `false` | boolean | | Numeric string (`123`, `3.14`) | number | | Everything else | string | | Any value with `--string` | string | + ### Output Format: Raw by Default
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
openspec/changes/add-config-command/design.md(1 hunks)openspec/changes/add-config-command/proposal.md(1 hunks)openspec/changes/add-config-command/specs/cli-config/spec.md(1 hunks)openspec/changes/add-config-command/tasks.md(1 hunks)src/cli/index.ts(2 hunks)src/commands/config.ts(1 hunks)src/core/completions/command-registry.ts(1 hunks)src/core/config-schema.ts(1 hunks)test/commands/config.test.ts(1 hunks)test/core/config-schema.test.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
openspec/changes/**/*.md
📄 CodeRabbit inference engine (openspec/AGENTS.md)
Scaffold proposal using
proposal.md,tasks.md, optionaldesign.md, and delta specs underopenspec/changes/<id>/
Files:
openspec/changes/add-config-command/proposal.mdopenspec/changes/add-config-command/design.mdopenspec/changes/add-config-command/tasks.mdopenspec/changes/add-config-command/specs/cli-config/spec.md
openspec/changes/*/proposal.md
📄 CodeRabbit inference engine (openspec/AGENTS.md)
Ensure
proposal.mdincludes sections: Why (1-2 sentences), What Changes (bullet list with breaking change markers), and Impact (affected specs and code)
Files:
openspec/changes/add-config-command/proposal.md
openspec/changes/*/tasks.md
📄 CodeRabbit inference engine (openspec/AGENTS.md)
Ensure
tasks.mdcontains implementation checklist with numbered sections and checkbox items
Files:
openspec/changes/add-config-command/tasks.md
openspec/changes/**/specs/**/spec.md
📄 CodeRabbit inference engine (openspec/AGENTS.md)
openspec/changes/**/specs/**/spec.md: Use## ADDED|MODIFIED|REMOVED|RENAMED Requirementsheaders in spec delta files
Include at least one#### Scenario:per requirement in spec delta files
Use#### Scenario: Nameformat (4 hashtags) for scenario headers, not bullets or bold text
Use## ADDED Requirementsfor new orthogonal capabilities that can stand alone; use## MODIFIED Requirementsfor behavior changes of existing requirements
When using MODIFIED Requirements, paste the full requirement block including header and all scenarios
Files:
openspec/changes/add-config-command/specs/cli-config/spec.md
🧠 Learnings (7)
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/**/*.md : Scaffold proposal using `proposal.md`, `tasks.md`, optional `design.md`, and delta specs under `openspec/changes/<id>/`
Applied to files:
openspec/changes/add-config-command/proposal.mdopenspec/changes/add-config-command/design.mdopenspec/changes/add-config-command/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/*/proposal.md : Ensure `proposal.md` includes sections: Why (1-2 sentences), What Changes (bullet list with breaking change markers), and Impact (affected specs and code)
Applied to files:
openspec/changes/add-config-command/proposal.mdopenspec/changes/add-config-command/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/**/specs/**/spec.md : Use `## ADDED Requirements` for new orthogonal capabilities that can stand alone; use `## MODIFIED Requirements` for behavior changes of existing requirements
Applied to files:
openspec/changes/add-config-command/proposal.mdopenspec/changes/add-config-command/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/**/specs/**/spec.md : Use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements` headers in spec delta files
Applied to files:
openspec/changes/add-config-command/proposal.mdopenspec/changes/add-config-command/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:02.839Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:02.839Z
Learning: Use `@/openspec/AGENTS.md` to learn how to create and apply change proposals, spec format and conventions, and project structure and guidelines
Applied to files:
openspec/changes/add-config-command/proposal.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Create `design.md` only when needed: cross-cutting changes, new external dependencies, significant data model changes, security/performance complexity, or pre-coding ambiguity
Applied to files:
openspec/changes/add-config-command/design.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/*/tasks.md : Ensure `tasks.md` contains implementation checklist with numbered sections and checkbox items
Applied to files:
openspec/changes/add-config-command/tasks.md
🧬 Code graph analysis (4)
test/core/config-schema.test.ts (1)
src/core/config-schema.ts (8)
getNestedValue(32-47)setNestedValue(57-71)deleteNestedValue(80-98)coerceValue(110-130)formatValueYaml(139-178)validateConfig(186-198)GlobalConfigSchema(7-14)DEFAULT_CONFIG(21-23)
src/cli/index.ts (1)
src/commands/config.ts (1)
registerConfigCommand(27-203)
src/commands/config.ts (1)
src/core/config-schema.ts (7)
formatValueYaml(139-178)getNestedValue(32-47)coerceValue(110-130)setNestedValue(57-71)validateConfig(186-198)deleteNestedValue(80-98)DEFAULT_CONFIG(21-23)
test/commands/config.test.ts (1)
src/core/completions/command-registry.ts (1)
COMMAND_REGISTRY(35-360)
🪛 LanguageTool
openspec/changes/add-config-command/design.md
[style] ~3-~3: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ...dit it by hand. This command provides a CLI interface to that config. ## Goals / Non-Goals ...
(ACRONYM_TAUTOLOGY)
openspec/changes/add-config-command/specs/cli-config/spec.md
[style] ~5-~5: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ...ig Specification ## Purpose Provide a CLI interface for viewing and modifying global OpenSp...
(ACRONYM_TAUTOLOGY)
🪛 markdownlint-cli2 (0.18.1)
openspec/changes/add-config-command/design.md
46-46: Tables should be surrounded by blank lines
(MD058, blanks-around-tables)
🔇 Additional comments (21)
openspec/changes/add-config-command/specs/cli-config/spec.md (1)
7-213: Spec structure follows guidelines correctly.The specification properly uses
## ADDED Requirementsfor new orthogonal capabilities, and all scenarios follow the#### Scenario: Nameformat as required. The WHEN/THEN/AND structure is consistent throughout.src/core/config-schema.ts (5)
7-23: Schema definition is well-structured.The use of
.passthrough()for forward compatibility with unknown fields is appropriate, and theDEFAULT_CONFIGcorrectly matches the schema structure.
32-47: LGTM!The
getNestedValuefunction correctly handles edge cases including null, undefined, and non-object intermediate values.
80-98: LGTM!The
deleteNestedValuefunction correctly returns a boolean indicating whether the key existed and was deleted. Same edge case consideration for empty paths applies here.
110-130: Well-implemented type coercion.The function correctly handles edge cases: empty strings are not coerced to
0(via thevalue.trim() !== ''check), and only exact case-sensitive"true"/"false"strings are coerced to booleans.
139-178: LGTM for intended use case.The YAML-like formatting handles primitives, arrays, and objects appropriately for human-readable config display.
src/cli/index.ts (2)
17-17: LGTM!Import follows the existing pattern for command registration.
204-204: LGTM!Registration follows the same pattern as
registerSpecCommand, placing the config command appropriately in the CLI initialization sequence.src/core/completions/command-registry.ts (1)
291-359: Config command registry entry is complete and consistent.The registry entry correctly defines all subcommands (path, list, get, set, unset, reset, edit) with their respective flags, matching the specification. The structure follows the existing patterns used by other commands like
specandcompletion.openspec/changes/add-config-command/proposal.md (1)
1-60: Proposal follows required structure.The proposal includes all required sections per coding guidelines:
- Why: Concise explanation of the user need (lines 1-3)
- What Changes: Bullet list with examples (lines 5-51)
- Impact: Affected specs and code listed (lines 53-60)
Based on learnings, the proposal correctly omits breaking change markers since this is additive functionality.
openspec/changes/add-config-command/tasks.md (1)
1-28: LGTM - Well-structured implementation checklist.The tasks file follows the required format with numbered sections and checkbox items. All 17 tasks are marked complete, covering core infrastructure, command implementation, integration, and testing. The organization is clear and comprehensive.
Based on coding guidelines, this properly implements the required tasks.md structure.
test/commands/config.test.ts (3)
12-37: Excellent test isolation setup.The test setup demonstrates good practices:
- Unique temp directories per test using timestamp and random suffix (line 14)
- Proper environment variable isolation and restoration (lines 18-19, 27)
- Module cache reset to pick up new environment variables (line 36)
- Spy setup and cleanup for console.error (lines 22, 33)
This ensures tests are fully isolated and won't interfere with each other or the actual config file.
39-92: Comprehensive integration test coverage.The tests cover all critical integration scenarios:
- Config path resolution with XDG_CONFIG_HOME
- Save/load round-trips
- Default behavior when config file is missing
- Unknown field preservation (passthrough validation)
- Graceful handling of invalid JSON with error logging
The use of dynamic imports (lines 40, 46, 54, 67, 81) correctly ensures each test gets a fresh module with the updated environment variables.
94-157: Thorough shell completion registry verification.The tests systematically verify:
- Config command exists in registry with correct description
- All 7 subcommands are present (path, list, get, set, unset, reset, edit)
- Subcommand-specific flags: --json on list, --string on set, --all/-y on reset
- Top-level --scope flag on config command
This ensures the completion registry stays synchronized with the command implementation.
test/core/config-schema.test.ts (4)
15-55: Excellent coverage of getNestedValue edge cases.The tests comprehensively cover:
- Top-level and nested dot-notation access (lines 16-24)
- Non-existent paths returning undefined (lines 26-34)
- Traversal through null and primitives (lines 36-44)
- Object and array value handling (lines 46-54)
This ensures robust handling of all access patterns mentioned in the design document.
57-93: Thorough setNestedValue testing.The tests validate critical behaviors:
- Top-level and nested value assignment
- Automatic creation of intermediate objects (line 70-74)
- Overwriting existing values and primitives (lines 76-86)
- Preservation of sibling keys (lines 88-92)
These scenarios ensure the dot-notation setter works correctly for all use cases.
129-180: Comprehensive type coercion test coverage.The tests validate all coercion rules from the design document:
- Boolean coercion for "true"/"false" (lines 130-136)
- Number coercion for integers, floats, negatives, scientific notation (lines 138-148, 177-179)
- String preservation for non-coercible values (lines 150-164)
- Force string flag override (lines 166-170)
- Infinity rejection per design (lines 172-175)
The edge case coverage (empty strings, whitespace, mixed alphanumeric) is excellent.
225-256: Solid validation testing with zod schema.The tests verify:
- Valid configurations with featureFlags (line 226-229)
- Empty and missing featureFlags (lines 231-239)
- Unknown field passthrough (lines 241-244) - critical for forward compatibility
- Rejection of invalid types (lines 246-255)
This aligns with the design decision to use zod with passthrough for forward compatibility.
src/commands/config.ts (3)
27-38: Good defensive validation for reserved scope flag.The preAction hook (lines 32-38) prevents usage of non-global scopes with a clear error message. This reserves the
--scopeflag for future project-local config implementation without breaking changes, as documented in the design.
84-111: Excellent validation-before-save pattern.The set command demonstrates best practices:
- Creates a deep copy for validation (line 93) before mutating the actual config
- Validates the new config with zod schema (lines 97-102)
- Only persists changes if validation passes (lines 105-106)
- Provides clear error messages on validation failure
This prevents saving invalid configurations that could break the tool.
130-157: Safe reset implementation with confirmation.The reset command includes good safeguards:
- Requires explicit
--allflag (lines 136-141) to prevent accidental resets- Prompts for confirmation unless
-y/--yesis provided (lines 143-152)- Uses the inquirer library for interactive confirmation with default to false (line 146)
This follows the principle of making destructive operations harder to execute accidentally.
…spaces Use spawn with shell: false and pass configPath as an argument instead of building a shell command string. This correctly handles spaces in both the EDITOR path and config file path on all platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/commands/config.ts (1)
159-198: Past review comment successfully addressed!The editor spawning now uses
spawn(editor, [configPath], { stdio: 'inherit', shell: false }), which correctly handles spaces in both the editor path and config path without shell parsing issues. This is the recommended approach and resolves the Windows compatibility concern from the previous review.
Consider validating config after edit.
Currently, the command doesn't validate the config file after the user closes the editor. If the user introduces syntax errors or schema violations during manual editing, these won't be detected until the config is next loaded, potentially causing confusing failures.
Optional: Add validation after editor closes
You could add validation after the editor closes to catch errors immediately:
await new Promise<void>((resolve, reject) => { child.on('close', (code) => { if (code === 0) { resolve(); } else { reject(new Error(`Editor exited with code ${code}`)); } }); child.on('error', reject); }); + + // Validate the edited config + try { + const editedConfig = getGlobalConfig(); + const validation = validateConfig(editedConfig); + if (!validation.success) { + console.error(`Warning: Configuration validation failed - ${validation.error}`); + console.error('Please fix the errors or run `openspec config reset --all -y` to restore defaults.'); + process.exitCode = 1; + } else { + console.log('Configuration validated successfully'); + } + } catch (error) { + console.error(`Error: Failed to load config - ${error instanceof Error ? error.message : 'Unknown error'}`); + console.error('The config file may contain invalid JSON. Please fix or reset.'); + process.exitCode = 1; + } }); }Note: This is optional, as many CLI tools trust users to manually validate their edits.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/commands/config.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/commands/config.ts (1)
src/core/config-schema.ts (7)
formatValueYaml(139-178)getNestedValue(32-47)coerceValue(110-130)setNestedValue(57-71)validateConfig(186-198)deleteNestedValue(80-98)DEFAULT_CONFIG(21-23)
🔇 Additional comments (2)
src/commands/config.ts (2)
63-80: LGTM! Silent exit is appropriate for scriptable output.The command correctly returns raw values suitable for scripting, with the exit code indicating success/failure. The lack of an error message when a key is not found is intentional to keep stdout clean for script consumption.
83-110: LGTM! Solid validation and error handling.The copy-before-validate pattern ensures that invalid configurations are rejected before any changes are persisted. The validation flow is well-structured and provides clear feedback to users.
Move completed change to archive and apply spec deltas to create the cli-config specification documenting the config command interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
openspec/changes/archive/2025-12-21-add-config-command/design.md (1)
3-3: Minor: Remove redundant phrase "CLI interface".The phrase "CLI interface" is tautological (I = interface). Per static analysis, simplify to "CLI".
🔎 Proposed fix
-The `global-config` spec defines how OpenSpec reads/writes `config.json`, but users currently must edit it by hand. This command provides a CLI interface to that config. +The `global-config` spec defines how OpenSpec reads/writes `config.json`, but users currently must edit it by hand. This command provides a CLI to that config.openspec/specs/cli-config/spec.md (1)
1-10: Minor: Remove redundant phrase "CLI interface".The phrase "CLI interface" is tautological. Per static analysis, simplify to "CLI" for clarity.
🔎 Proposed fix
-## Purpose -Provide a user-friendly CLI interface for viewing and modifying global OpenSpec configuration settings without manually editing JSON files. +## Purpose +Provide a user-friendly CLI for viewing and modifying global OpenSpec configuration settings without manually editing JSON files.openspec/changes/archive/2025-12-21-add-config-command/specs/cli-config/spec.md (1)
1-10: Minor: Remove redundant phrase "CLI interface".The phrase "CLI interface" is tautological. Per static analysis, simplify to "CLI" for consistency.
🔎 Proposed fix
-## Purpose - -Provide a CLI interface for viewing and modifying global OpenSpec configuration. Enables users to manage settings without manually editing JSON files, with support for scripting and automation. +## Purpose + +Provide a CLI for viewing and modifying global OpenSpec configuration. Enables users to manage settings without manually editing JSON files, with support for scripting and automation.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
openspec/changes/archive/2025-12-21-add-config-command/design.md(1 hunks)openspec/changes/archive/2025-12-21-add-config-command/proposal.md(1 hunks)openspec/changes/archive/2025-12-21-add-config-command/specs/cli-config/spec.md(1 hunks)openspec/changes/archive/2025-12-21-add-config-command/tasks.md(1 hunks)openspec/specs/cli-config/spec.md(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
openspec/changes/**/*.md
📄 CodeRabbit inference engine (openspec/AGENTS.md)
Scaffold proposal using
proposal.md,tasks.md, optionaldesign.md, and delta specs underopenspec/changes/<id>/
Files:
openspec/changes/archive/2025-12-21-add-config-command/proposal.mdopenspec/changes/archive/2025-12-21-add-config-command/specs/cli-config/spec.mdopenspec/changes/archive/2025-12-21-add-config-command/tasks.mdopenspec/changes/archive/2025-12-21-add-config-command/design.md
openspec/changes/**/specs/**/spec.md
📄 CodeRabbit inference engine (openspec/AGENTS.md)
openspec/changes/**/specs/**/spec.md: Use## ADDED|MODIFIED|REMOVED|RENAMED Requirementsheaders in spec delta files
Include at least one#### Scenario:per requirement in spec delta files
Use#### Scenario: Nameformat (4 hashtags) for scenario headers, not bullets or bold text
Use## ADDED Requirementsfor new orthogonal capabilities that can stand alone; use## MODIFIED Requirementsfor behavior changes of existing requirements
When using MODIFIED Requirements, paste the full requirement block including header and all scenarios
Files:
openspec/changes/archive/2025-12-21-add-config-command/specs/cli-config/spec.md
openspec/specs/**/spec.md
📄 CodeRabbit inference engine (openspec/AGENTS.md)
Use SHALL/MUST for normative requirements in spec files; avoid should/may unless intentionally non-normative
Files:
openspec/specs/cli-config/spec.md
🧠 Learnings (7)
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/**/*.md : Scaffold proposal using `proposal.md`, `tasks.md`, optional `design.md`, and delta specs under `openspec/changes/<id>/`
Applied to files:
openspec/changes/archive/2025-12-21-add-config-command/proposal.mdopenspec/specs/cli-config/spec.mdopenspec/changes/archive/2025-12-21-add-config-command/tasks.mdopenspec/changes/archive/2025-12-21-add-config-command/design.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/*/proposal.md : Ensure `proposal.md` includes sections: Why (1-2 sentences), What Changes (bullet list with breaking change markers), and Impact (affected specs and code)
Applied to files:
openspec/changes/archive/2025-12-21-add-config-command/proposal.mdopenspec/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:02.839Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:02.839Z
Learning: Use `@/openspec/AGENTS.md` to learn how to create and apply change proposals, spec format and conventions, and project structure and guidelines
Applied to files:
openspec/changes/archive/2025-12-21-add-config-command/proposal.mdopenspec/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/**/specs/**/spec.md : Use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements` headers in spec delta files
Applied to files:
openspec/changes/archive/2025-12-21-add-config-command/proposal.mdopenspec/changes/archive/2025-12-21-add-config-command/specs/cli-config/spec.mdopenspec/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/**/specs/**/spec.md : Use `## ADDED Requirements` for new orthogonal capabilities that can stand alone; use `## MODIFIED Requirements` for behavior changes of existing requirements
Applied to files:
openspec/changes/archive/2025-12-21-add-config-command/specs/cli-config/spec.mdopenspec/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/*/tasks.md : Ensure `tasks.md` contains implementation checklist with numbered sections and checkbox items
Applied to files:
openspec/changes/archive/2025-12-21-add-config-command/tasks.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Create `design.md` only when needed: cross-cutting changes, new external dependencies, significant data model changes, security/performance complexity, or pre-coding ambiguity
Applied to files:
openspec/changes/archive/2025-12-21-add-config-command/design.md
🪛 LanguageTool
openspec/changes/archive/2025-12-21-add-config-command/specs/cli-config/spec.md
[style] ~5-~5: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ...ig Specification ## Purpose Provide a CLI interface for viewing and modifying global OpenSp...
(ACRONYM_TAUTOLOGY)
openspec/specs/cli-config/spec.md
[style] ~4-~4: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ...ion ## Purpose Provide a user-friendly CLI interface for viewing and modifying global OpenSp...
(ACRONYM_TAUTOLOGY)
openspec/changes/archive/2025-12-21-add-config-command/design.md
[style] ~3-~3: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ...dit it by hand. This command provides a CLI interface to that config. ## Goals / Non-Goals ...
(ACRONYM_TAUTOLOGY)
🔇 Additional comments (2)
openspec/changes/archive/2025-12-21-add-config-command/tasks.md (1)
1-28: LGTM — Well-structured implementation checklist.The tasks are clearly organized with numbered sections and checkbox items, all marked complete, indicating the feature is comprehensively implemented.
openspec/changes/archive/2025-12-21-add-config-command/proposal.md (1)
1-60: LGTM — Comprehensive and well-structured proposal.The proposal clearly articulates the "Why," detailed "What Changes" with usage examples, and impact on affected specs and code. Structure and content align with guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
openspec/specs/cli-config/spec.md (1)
1-217: Excellent specification with proper normative language!The spec consistently uses SHALL for all normative requirements as required by the coding guidelines. The requirements are comprehensive, well-structured, and thoroughly cover all aspects of the config command behavior, including edge cases, error handling, and output formats.
Optional: Minor style refinement
Line 4 uses "CLI interface" which is technically redundant since CLI already means "Command Line Interface." You could simplify to just "CLI" if desired, though this is purely stylistic.
-Provide a user-friendly CLI interface for viewing and modifying global OpenSpec configuration settings without manually editing JSON files. +Provide a user-friendly CLI for viewing and modifying global OpenSpec configuration settings without manually editing JSON files.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
openspec/specs/cli-config/spec.mdsrc/cli/index.tssrc/commands/config.tssrc/core/completions/command-registry.tssrc/core/config-schema.tstest/commands/config.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/core/completions/command-registry.ts
- src/core/config-schema.ts
🧰 Additional context used
📓 Path-based instructions (1)
openspec/specs/**/spec.md
📄 CodeRabbit inference engine (openspec/AGENTS.md)
Use SHALL/MUST for normative requirements in spec files; avoid should/may unless intentionally non-normative
Files:
openspec/specs/cli-config/spec.md
🧠 Learnings (6)
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/**/*.md : Scaffold proposal using `proposal.md`, `tasks.md`, optional `design.md`, and delta specs under `openspec/changes/<id>/`
Applied to files:
openspec/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/*/proposal.md : Ensure `proposal.md` includes sections: Why (1-2 sentences), What Changes (bullet list with breaking change markers), and Impact (affected specs and code)
Applied to files:
openspec/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/**/specs/**/spec.md : Use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements` headers in spec delta files
Applied to files:
openspec/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:02.839Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:02.839Z
Learning: Use `@/openspec/AGENTS.md` to learn how to create and apply change proposals, spec format and conventions, and project structure and guidelines
Applied to files:
openspec/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Check `openspec/project.md` for project conventions before creating specs
Applied to files:
openspec/specs/cli-config/spec.md
📚 Learning: 2025-11-25T01:08:19.004Z
Learnt from: CR
Repo: Fission-AI/OpenSpec PR: 0
File: openspec/AGENTS.md:0-0
Timestamp: 2025-11-25T01:08:19.004Z
Learning: Applies to openspec/changes/**/specs/**/spec.md : Use `## ADDED Requirements` for new orthogonal capabilities that can stand alone; use `## MODIFIED Requirements` for behavior changes of existing requirements
Applied to files:
openspec/specs/cli-config/spec.md
🧬 Code graph analysis (3)
src/cli/index.ts (1)
src/commands/config.ts (1)
registerConfigCommand(27-233)
src/commands/config.ts (1)
src/core/config-schema.ts (8)
formatValueYaml(171-210)getNestedValue(64-79)validateConfigKeyPath(31-55)coerceValue(142-162)setNestedValue(89-103)validateConfig(218-230)deleteNestedValue(112-130)DEFAULT_CONFIG(21-23)
test/commands/config.test.ts (2)
src/core/completions/command-registry.ts (1)
COMMAND_REGISTRY(35-364)src/core/config-schema.ts (1)
validateConfigKeyPath(31-55)
🪛 LanguageTool
openspec/specs/cli-config/spec.md
[style] ~4-~4: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ...ion ## Purpose Provide a user-friendly CLI interface for viewing and modifying global OpenSp...
(ACRONYM_TAUTOLOGY)
🔇 Additional comments (12)
src/cli/index.ts (2)
16-16: LGTM!The import follows the established pattern for command registration functions.
204-204: LGTM!The config command registration is correctly placed and follows the established pattern for command integration.
test/commands/config.test.ts (3)
6-92: Excellent test isolation and coverage!The integration test suite properly isolates each test with unique temporary directories, environment variable overrides, and module cache resets. The tests comprehensively cover config path resolution, persistence, defaults, unknown field preservation, and invalid JSON handling.
94-158: LGTM!The shell completion registry tests thoroughly verify that all config subcommands and their flags are properly registered for completion support.
160-175: LGTM!The key validation tests properly verify the schema validation rules for top-level keys, nested feature flags, and disallowed deep nesting.
src/commands/config.ts (7)
27-38: LGTM!The command registration properly enforces global scope and reserves the
--scopeflag for future project-local configuration support, exactly as specified in the requirements.
41-61: LGTM!The path and list subcommands are implemented correctly with proper output formatting for both human-readable (YAML-like) and JSON modes.
64-81: LGTM!The get command correctly implements nested key access with dot notation, appropriate exit codes for missing keys, and proper output formatting for both scalar and object values.
84-123: Excellent defensive implementation!The set command implements robust validation with copy-before-modify to ensure config integrity. The key validation provides clear error messages and user guidance, while the schema validation prevents invalid configurations from being persisted.
126-139: LGTM!The unset command correctly handles both existent and non-existent keys, saving only when necessary and providing appropriate user feedback.
142-169: LGTM!The reset command properly implements the safety requirements with explicit --all flag, confirmation prompt (unless --yes), and clear usage guidance. The spreading of DEFAULT_CONFIG ensures a clean copy is saved.
172-232: LGTM! Windows path handling properly addressed.The edit command correctly spawns the editor using
spawn(editor, [configPath], { shell: false }), which avoids shell parsing issues and properly handles paths with spaces on all platforms including Windows. The post-edit validation ensures config integrity, and comprehensive error handling covers various failure scenarios.
The config command (added in #382) reintroduced the pre-commit hook hang issue that was fixed in #380. The static import of @inquirer/prompts at module load time causes stdin event listeners to be registered even when running non-interactive commands, preventing clean process exit when stdin is piped (as pre-commit does). Convert the static import to a dynamic import that only loads inquirer when the `config reset` command is actually used interactively. Fixes #367
…392) * fix(cli): use dynamic import for @inquirer/prompts in config command The config command (added in #382) reintroduced the pre-commit hook hang issue that was fixed in #380. The static import of @inquirer/prompts at module load time causes stdin event listeners to be registered even when running non-interactive commands, preventing clean process exit when stdin is piped (as pre-commit does). Convert the static import to a dynamic import that only loads inquirer when the `config reset` command is actually used interactively. Fixes #367 * chore: add ESLint with no-restricted-imports rule for @InQuirer Add ESLint configuration that prevents static imports of @inquirer/* modules. This prevents future regressions of the pre-commit hook hang issue fixed in this PR. The rule shows a helpful error message pointing to issue #367 for context. init.ts is exempted since it's already dynamically imported from the CLI. * ci: add ESLint step to lint job Run `pnpm lint` in CI to enforce the no-restricted-imports rule that prevents static @InQuirer imports.
* feat(cli): add openspec config command for global configuration management (Fission-AI#382) * feat(cli): add openspec config command for global configuration management Implements the `openspec config` command with subcommands: - `path`: Show config file location - `list [--json]`: Show all current settings - `get <key>`: Get a specific value (raw output for scripting) - `set <key> <value> [--string]`: Set a value with auto type coercion - `unset <key>`: Remove a key (revert to default) - `reset --all [-y]`: Reset configuration to defaults - `edit`: Open config in $EDITOR/$VISUAL Key features: - Dot notation for nested key access (e.g., featureFlags.someFlag) - Auto type coercion (true/false → boolean, numbers → number) - --string flag to force string storage - Zod schema validation with unknown field passthrough - Reserved --scope flag for future project-local config - Windows-compatible editor spawning with proper path quoting - Shell completion registry integration * test(config): add additional unit tests for validation and coercion - Add tests for unknown fields with various types - Add test to verify error message path for featureFlags - Add test for number values rejection in featureFlags - Add config set simulation tests to verify full coerce → set → validate flow * fix(config): avoid shell parsing in config edit to handle paths with spaces Use spawn with shell: false and pass configPath as an argument instead of building a shell command string. This correctly handles spaces in both the EDITOR path and config file path on all platforms. * chore(openspec): archive add-config-command and create cli-config spec Move completed change to archive and apply spec deltas to create the cli-config specification documenting the config command interface. * Validate config keys on set * Add changeset for config command and shell completions (Fission-AI#388) * chore(release): version packages (Fission-AI#389) * Version Packages * chore: trigger CI --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tabish Bidiwale <[email protected]> * feat(ci): migrate to npm OIDC trusted publishing (Fission-AI#390) Replace classic npm token authentication with OIDC trusted publishing: - Add `id-token: write` permission for OIDC token generation - Upgrade to Node 24 (includes npm 11.5.1+ required for OIDC) - Remove NPM_TOKEN/NODE_AUTH_TOKEN env vars (OIDC replaces them) This eliminates the need for rotating npm access tokens and provides cryptographically verified publisher identity with automatic provenance attestation. Requires configuring trusted publisher on npmjs.com: - Organization: Fission-AI - Repository: OpenSpec - Workflow: release-prepare.yml * fix(cli): use dynamic import for @inquirer/prompts in config command (Fission-AI#392) * fix(cli): use dynamic import for @inquirer/prompts in config command The config command (added in Fission-AI#382) reintroduced the pre-commit hook hang issue that was fixed in Fission-AI#380. The static import of @inquirer/prompts at module load time causes stdin event listeners to be registered even when running non-interactive commands, preventing clean process exit when stdin is piped (as pre-commit does). Convert the static import to a dynamic import that only loads inquirer when the `config reset` command is actually used interactively. Fixes Fission-AI#367 * chore: add ESLint with no-restricted-imports rule for @InQuirer Add ESLint configuration that prevents static imports of @inquirer/* modules. This prevents future regressions of the pre-commit hook hang issue fixed in this PR. The rule shows a helpful error message pointing to issue Fission-AI#367 for context. init.ts is exempted since it's already dynamically imported from the CLI. * ci: add ESLint step to lint job Run `pnpm lint` in CI to enforce the no-restricted-imports rule that prevents static @InQuirer imports. * Add changeset for config command dynamic import fix (Fission-AI#393) * chore(release): version packages (Fission-AI#394) * Version Packages * chore: trigger CI --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tabish Bidiwale <[email protected]> * fix(cli): respect --no-interactive flag in validate command (Fission-AI#395) * fix(cli): respect --no-interactive flag in validate command The validate command's spinner was starting regardless of the --no-interactive flag, causing hangs in pre-commit hooks. Changes: - Pass noInteractive option to runBulkValidation - Handle Commander.js --no-* flag syntax (sets interactive=false) - Only start ora spinner when in interactive mode - Add CI environment variable check to isInteractive() for industry standard compliance * test: add unit tests for interactive utilities and CLI flag - Export resolveNoInteractive() helper for reuse - Add InteractiveOptions type export for testing - Refactor validate.ts to use resolveNoInteractive() - Add 17 unit tests for isInteractive() and resolveNoInteractive() - Add CLI integration test for --no-interactive flag This prevents future regressions where Commander.js --no-* flag parsing is not properly handled. * Add changeset for --no-interactive flag fix (Fission-AI#396) * chore(release): version packages (Fission-AI#397) * Version Packages * chore: trigger CI --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tabish Bidiwale <[email protected]> * docs: add artifact POC analysis document (Fission-AI#398) Add internal documentation for the artifact-based approach to OpenSpec core. This document outlines design decisions, terminology, and the philosophy behind treating dependencies as enablers rather than gates. * fix(archive): allow REMOVED requirements when creating new spec files (Fission-AI#403) (Fission-AI#404) When creating a new spec file, REMOVED requirements are now ignored with a warning instead of causing archive to fail. This enables refactoring scenarios where old fields are removed while documenting a capability for the first time. Fixes Fission-AI#403 --------- Co-authored-by: Tabish Bidiwale <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tabish Bidiwale <[email protected]> Co-authored-by: Eunsong-Park <[email protected]>
…ement (Fission-AI#382) * feat(cli): add openspec config command for global configuration management Implements the `openspec config` command with subcommands: - `path`: Show config file location - `list [--json]`: Show all current settings - `get <key>`: Get a specific value (raw output for scripting) - `set <key> <value> [--string]`: Set a value with auto type coercion - `unset <key>`: Remove a key (revert to default) - `reset --all [-y]`: Reset configuration to defaults - `edit`: Open config in $EDITOR/$VISUAL Key features: - Dot notation for nested key access (e.g., featureFlags.someFlag) - Auto type coercion (true/false → boolean, numbers → number) - --string flag to force string storage - Zod schema validation with unknown field passthrough - Reserved --scope flag for future project-local config - Windows-compatible editor spawning with proper path quoting - Shell completion registry integration * test(config): add additional unit tests for validation and coercion - Add tests for unknown fields with various types - Add test to verify error message path for featureFlags - Add test for number values rejection in featureFlags - Add config set simulation tests to verify full coerce → set → validate flow * fix(config): avoid shell parsing in config edit to handle paths with spaces Use spawn with shell: false and pass configPath as an argument instead of building a shell command string. This correctly handles spaces in both the EDITOR path and config file path on all platforms. * chore(openspec): archive add-config-command and create cli-config spec Move completed change to archive and apply spec deltas to create the cli-config specification documenting the config command interface. * Validate config keys on set
…ission-AI#392) * fix(cli): use dynamic import for @inquirer/prompts in config command The config command (added in Fission-AI#382) reintroduced the pre-commit hook hang issue that was fixed in Fission-AI#380. The static import of @inquirer/prompts at module load time causes stdin event listeners to be registered even when running non-interactive commands, preventing clean process exit when stdin is piped (as pre-commit does). Convert the static import to a dynamic import that only loads inquirer when the `config reset` command is actually used interactively. Fixes Fission-AI#367 * chore: add ESLint with no-restricted-imports rule for @InQuirer Add ESLint configuration that prevents static imports of @inquirer/* modules. This prevents future regressions of the pre-commit hook hang issue fixed in this PR. The rule shows a helpful error message pointing to issue Fission-AI#367 for context. init.ts is exempted since it's already dynamically imported from the CLI. * ci: add ESLint step to lint job Run `pnpm lint` in CI to enforce the no-restricted-imports rule that prevents static @InQuirer imports.
…ement (Fission-AI#382) * feat(cli): add openspec config command for global configuration management Implements the `openspec config` command with subcommands: - `path`: Show config file location - `list [--json]`: Show all current settings - `get <key>`: Get a specific value (raw output for scripting) - `set <key> <value> [--string]`: Set a value with auto type coercion - `unset <key>`: Remove a key (revert to default) - `reset --all [-y]`: Reset configuration to defaults - `edit`: Open config in $EDITOR/$VISUAL Key features: - Dot notation for nested key access (e.g., featureFlags.someFlag) - Auto type coercion (true/false → boolean, numbers → number) - --string flag to force string storage - Zod schema validation with unknown field passthrough - Reserved --scope flag for future project-local config - Windows-compatible editor spawning with proper path quoting - Shell completion registry integration * test(config): add additional unit tests for validation and coercion - Add tests for unknown fields with various types - Add test to verify error message path for featureFlags - Add test for number values rejection in featureFlags - Add config set simulation tests to verify full coerce → set → validate flow * fix(config): avoid shell parsing in config edit to handle paths with spaces Use spawn with shell: false and pass configPath as an argument instead of building a shell command string. This correctly handles spaces in both the EDITOR path and config file path on all platforms. * chore(openspec): archive add-config-command and create cli-config spec Move completed change to archive and apply spec deltas to create the cli-config specification documenting the config command interface. * Validate config keys on set
…ission-AI#392) * fix(cli): use dynamic import for @inquirer/prompts in config command The config command (added in Fission-AI#382) reintroduced the pre-commit hook hang issue that was fixed in Fission-AI#380. The static import of @inquirer/prompts at module load time causes stdin event listeners to be registered even when running non-interactive commands, preventing clean process exit when stdin is piped (as pre-commit does). Convert the static import to a dynamic import that only loads inquirer when the `config reset` command is actually used interactively. Fixes Fission-AI#367 * chore: add ESLint with no-restricted-imports rule for @InQuirer Add ESLint configuration that prevents static imports of @inquirer/* modules. This prevents future regressions of the pre-commit hook hang issue fixed in this PR. The rule shows a helpful error message pointing to issue Fission-AI#367 for context. init.ts is exempted since it's already dynamically imported from the CLI. * ci: add ESLint step to lint job Run `pnpm lint` in CI to enforce the no-restricted-imports rule that prevents static @InQuirer imports.
…ement (Fission-AI#382) * feat(cli): add openspec config command for global configuration management Implements the `openspec config` command with subcommands: - `path`: Show config file location - `list [--json]`: Show all current settings - `get <key>`: Get a specific value (raw output for scripting) - `set <key> <value> [--string]`: Set a value with auto type coercion - `unset <key>`: Remove a key (revert to default) - `reset --all [-y]`: Reset configuration to defaults - `edit`: Open config in $EDITOR/$VISUAL Key features: - Dot notation for nested key access (e.g., featureFlags.someFlag) - Auto type coercion (true/false → boolean, numbers → number) - --string flag to force string storage - Zod schema validation with unknown field passthrough - Reserved --scope flag for future project-local config - Windows-compatible editor spawning with proper path quoting - Shell completion registry integration * test(config): add additional unit tests for validation and coercion - Add tests for unknown fields with various types - Add test to verify error message path for featureFlags - Add test for number values rejection in featureFlags - Add config set simulation tests to verify full coerce → set → validate flow * fix(config): avoid shell parsing in config edit to handle paths with spaces Use spawn with shell: false and pass configPath as an argument instead of building a shell command string. This correctly handles spaces in both the EDITOR path and config file path on all platforms. * chore(openspec): archive add-config-command and create cli-config spec Move completed change to archive and apply spec deltas to create the cli-config specification documenting the config command interface. * Validate config keys on set
…ission-AI#392) * fix(cli): use dynamic import for @inquirer/prompts in config command The config command (added in Fission-AI#382) reintroduced the pre-commit hook hang issue that was fixed in Fission-AI#380. The static import of @inquirer/prompts at module load time causes stdin event listeners to be registered even when running non-interactive commands, preventing clean process exit when stdin is piped (as pre-commit does). Convert the static import to a dynamic import that only loads inquirer when the `config reset` command is actually used interactively. Fixes Fission-AI#367 * chore: add ESLint with no-restricted-imports rule for @InQuirer Add ESLint configuration that prevents static imports of @inquirer/* modules. This prevents future regressions of the pre-commit hook hang issue fixed in this PR. The rule shows a helpful error message pointing to issue Fission-AI#367 for context. init.ts is exempted since it's already dynamically imported from the CLI. * ci: add ESLint step to lint job Run `pnpm lint` in CI to enforce the no-restricted-imports rule that prevents static @InQuirer imports.
Summary
openspec configcommand with full subcommand suite for managing global configurationNew Subcommands
config pathconfig list [--json]config get <key>config set <key> <value> [--string]config unset <key>config reset --all [-y]config editKey Features
featureFlags.someFlag)true/false→ boolean, numeric strings → number--stringflag to force string storage (e.g., store literal "true")--scopeflag for future project-local config supportTest plan
npm test)featureFlags🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests
✏️ Tip: You can customize this high-level summary in your review settings.