-
Notifications
You must be signed in to change notification settings - Fork 0
feat(cli): add external issue tracking support #2
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
…-AI#378) Prioritize XDG_CONFIG_HOME on Windows to fix test environment overrides. Previously, Windows would always use APPDATA regardless of XDG_CONFIG_HOME, causing tests to fail. Now XDG_CONFIG_HOME is checked first on all platforms before falling back to platform-specific defaults. Also update the Windows APPDATA test to explicitly clear XDG_CONFIG_HOME when testing the fallback behavior.
…ission-AI#380) Fixes Fission-AI#367 The CLI was hanging when run as a pre-commit hook because @inquirer/prompts was statically imported at module load time. Even when prompts were never called (e.g., `openspec validate --specs --no-interactive`), the import itself could set up stdin references that prevented clean process exit when stdin was piped. Changes: - Convert all static `@inquirer/prompts` imports to dynamic imports - Dynamically import `InitCommand` (which uses `@inquirer/core`) - Update `isInteractive()` to accept options object with both `noInteractive` and Commander's negated `interactive` property - Handle empty validation queue with proper exit code Now when running in non-interactive mode, the inquirer modules are never loaded, allowing the process to exit cleanly after completion.
- Add `plx` as an alias command alongside `openspec` - Create OpenSplx pixel art logo assets (light/dark themes) - Update README with fork notice and Quick Start section - Make CLI command name dynamic based on invocation - Update completion system to support both command names - Add command-name utility for detecting invoked command
- Add YAML frontmatter parsing for tracked issues in proposal.md - Display issue identifiers in `openspec list` output - Include trackedIssues in `openspec show --json` output - Report tracked issues when archiving changes - Add External Issue Tracking section to AGENTS.md template - Add TrackedIssue schema and type exports
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.
Pull request overview
This PR adds external issue tracking support to the OpenSpec CLI, enabling proposals to reference external issues (Linear, GitHub, Jira, etc.) via YAML frontmatter. It also includes rebranding changes to support the OpenSplx fork with a plx command alias, along with several refactoring improvements for better code organization and user experience.
Key changes include:
- External Issue Tracking: YAML frontmatter parsing in proposal.md to store tracked issue references (tracker, id, url), with display support across CLI commands (list, show, archive)
- Branding Updates: Addition of
plxcommand alias, new logo assets, and updated README with OpenSplx fork documentation - CLI Improvements: Dynamic imports for interactive prompts, improved command name detection, XDG Base Directory compliance for global config, and better handling of empty validation queues
Reviewed changes
Copilot reviewed 30 out of 33 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/core/parsers/markdown-parser.ts | Adds YAML frontmatter extraction with simple parser for tracked-issues field |
| src/core/parsers/change-parser.ts | Integrates frontmatter parsing to include trackedIssues in Change objects |
| src/core/schemas/change.schema.ts | Defines TrackedIssue schema (tracker, id, url) and adds optional trackedIssues array to Change schema |
| src/core/schemas/index.ts | Exports TrackedIssueSchema and TrackedIssue type |
| src/core/list.ts | Displays first tracked issue ID in parentheses after change name |
| src/commands/change.ts | Includes trackedIssues in JSON output and long format display |
| src/core/archive.ts | Reports tracked issues when archiving changes, uses dynamic imports for prompts |
| src/commands/validate.ts | Adds empty queue handling, uses dynamic imports for prompts |
| src/commands/show.ts | Uses dynamic imports for prompts |
| src/commands/spec.ts | Uses dynamic imports for prompts |
| src/commands/completion.ts | Uses command name from utility for dynamic completion generation |
| src/utils/interactive.ts | Refactors to support both boolean and options object parameters for better flexibility |
| src/utils/command-name.ts | New utility to detect CLI command name (openspec vs plx) from invocation path |
| src/core/global-config.ts | Moves XDG_CONFIG_HOME check to take precedence on all platforms |
| src/core/completions/types.ts | Adds optional commandName parameter to CompletionGenerator.generate() |
| src/core/completions/generators/zsh-generator.ts | Supports dynamic command name in generated completion scripts |
| src/core/templates/agents-template.ts | Adds External Issue Tracking section with guidance for agents |
| src/cli/index.ts | Uses dynamic command name and converts --no-color flag check to opts.color === false |
| scripts/postinstall.js | Updates completion installation tips to mention both openspec and plx commands |
| bin/plx.js | New entry point for plx command alias |
| package.json | Adds plx binary entry |
| assets/opensplx_pixel_*.svg | New logo assets for OpenSplx branding |
| README.md | Adds OpenSplx fork notice and quick start guide |
| openspec/AGENTS.md | Includes External Issue Tracking guidance for agents |
| openspec/changes/add-external-issue-tracking/* | Spec files, tasks, and proposal documenting the external issue tracking feature |
| test/core/global-config.test.ts | Updates test description for Windows XDG_CONFIG_HOME behavior |
| test/core/completions/generators/zsh-generator.test.ts | Updates test expectation for lowercase 'openspec' in comment |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/core/list.ts
Outdated
| const issueDisplay = change.trackedIssue ? ` (${change.trackedIssue})` : ''; | ||
| const status = formatTaskStatus({ total: change.totalTasks, completed: change.completedTasks }); | ||
| console.log(`${padding}${paddedName} ${status}`); | ||
| console.log(`${padding}${paddedName}${issueDisplay} ${status}`); |
Copilot
AI
Dec 21, 2025
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.
The padding calculation doesn't account for the tracked issue display length. When different changes have different length issue IDs (or some have no issues), the alignment of the status column will be inconsistent. Consider calculating nameWidth to include the issue display, or adjusting the padding after adding the issue display.
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.
Fixed. Width calculation now includes the full display name with issue identifier. Added unit tests to verify alignment with varying issue ID lengths.
| if (currentIssue && currentIssue.tracker && currentIssue.id && currentIssue.url) { | ||
| trackedIssues.push(currentIssue as TrackedIssue); | ||
| } |
Copilot
AI
Dec 21, 2025
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.
The YAML parser doesn't validate that all three required fields (tracker, id, url) are present before pushing to trackedIssues. While the schema validation will catch this later, it would be better to handle malformed YAML more gracefully by either logging a warning or skipping incomplete issue entries during parsing.
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.
Keeping as-is. The code already validates all three fields before pushing: if (currentIssue.tracker && currentIssue.id && currentIssue.url). Malformed entries are silently skipped, which is intentional for graceful degradation.
src/utils/command-name.ts
Outdated
| const scriptName = path.basename(scriptPath).replace(/\.js$/, ''); | ||
| return scriptName === 'plx' ? 'plx' : 'openspec'; |
Copilot
AI
Dec 21, 2025
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.
The command name detection only checks if the script name equals 'plx' but doesn't handle other potential edge cases like 'plx.exe' on Windows, or if the script is executed through npx/pnpm exec. Consider normalizing the script name more robustly or using a case-insensitive comparison.
| const scriptName = path.basename(scriptPath).replace(/\.js$/, ''); | |
| return scriptName === 'plx' ? 'plx' : 'openspec'; | |
| const rawScriptName = path.basename(scriptPath); | |
| const normalizedScriptName = rawScriptName | |
| .toLowerCase() | |
| .replace(/\.(js|cjs|mjs|ts|cmd|exe|bat)$/, ''); | |
| return normalizedScriptName === 'plx' ? 'plx' : 'openspec'; |
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.
Fixed. Now handles Windows extensions (.exe, .cmd, .bat), Node.js module extensions (.cjs, .mjs, .ts), case-insensitive matching, and cross-platform path separators. Added 19 unit tests covering all scenarios.
| // Check if shell is supported | ||
| if (!CompletionFactory.isSupported(shell)) { | ||
| console.log(`\nTip: Run 'openspec completion install' for shell completions`); | ||
| console.log(`\nTip: Run 'openspec completion install' or 'plx completion install' for shell completions`); |
Copilot
AI
Dec 21, 2025
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.
The generator.generate() call doesn't specify a commandName parameter, so it defaults to 'openspec'. This means completions generated during postinstall won't work for the 'plx' command. Consider detecting which command name to use or generating completions for both command names.
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.
Fixed. postinstall.js now generates and installs completions for both 'openspec' and 'plx' command names. Updated ZshInstaller.install() and getInstallationPath() to accept a commandName parameter. Added unit tests for multi-command installation.
src/commands/change.ts
Outdated
| const issueText = change.trackedIssues && change.trackedIssues.length > 0 | ||
| ? ` (${change.trackedIssues[0].id})` | ||
| : ''; | ||
| console.log(`${changeName}${issueText}: ${title}${deltaCountText}${taskStatusText}`); |
Copilot
AI
Dec 21, 2025
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.
The tracked issue display format is inconsistent across commands. In list.ts, it appears after the name and before the status. In change.ts long format, it appears after the name but before the colon and title. While not a critical issue, consider standardizing the format across all commands for better consistency (e.g., always after the name in parentheses).
| console.log(`${changeName}${issueText}: ${title}${deltaCountText}${taskStatusText}`); | |
| console.log(`${changeName}: ${title}${issueText}${deltaCountText}${taskStatusText}`); |
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.
Fixed. Issue display now appears after the title in long format: changeName: title (ISSUE) [deltas] [tasks]. This keeps the name:title pair together while still showing the issue reference. Added unit tests to verify the format order.
- Fix list.ts alignment to include issue display in width calculation - Fix command-name.ts to handle Windows extensions and cross-platform paths - Fix postinstall.js to install completions for both openspec and plx - Fix change.ts issue display format (after title in long format) - Add comprehensive unit tests for all fixes - Archive add-external-issue-tracking change with spec updates
Keep improved cross-platform command-name detection and dual-command completion installation from this branch.
* fix(global-config): respect XDG_CONFIG_HOME on all platforms (Fission-AI#378) Prioritize XDG_CONFIG_HOME on Windows to fix test environment overrides. Previously, Windows would always use APPDATA regardless of XDG_CONFIG_HOME, causing tests to fail. Now XDG_CONFIG_HOME is checked first on all platforms before falling back to platform-specific defaults. Also update the Windows APPDATA test to explicitly clear XDG_CONFIG_HOME when testing the fallback behavior. * fix(cli): prevent hang in pre-commit hooks by using dynamic imports (Fission-AI#380) Fixes Fission-AI#367 The CLI was hanging when run as a pre-commit hook because @inquirer/prompts was statically imported at module load time. Even when prompts were never called (e.g., `openspec validate --specs --no-interactive`), the import itself could set up stdin references that prevented clean process exit when stdin was piped. Changes: - Convert all static `@inquirer/prompts` imports to dynamic imports - Dynamically import `InitCommand` (which uses `@inquirer/core`) - Update `isInteractive()` to accept options object with both `noInteractive` and Commander's negated `interactive` property - Handle empty validation queue with proper exit code Now when running in non-interactive mode, the inquirer modules are never loaded, allowing the process to exit cleanly after completion. * feat(cli): add plx command alias and rebrand as OpenSplx (OpenSplx-#1) - Add `plx` as an alias command alongside `openspec` - Create OpenSplx pixel art logo assets (light/dark themes) - Update README with fork notice and Quick Start section - Make CLI command name dynamic based on invocation - Update completion system to support both command names - Add command-name utility for detecting invoked command * feat(cli): add external issue tracking support - Add YAML frontmatter parsing for tracked issues in proposal.md - Display issue identifiers in `openspec list` output - Include trackedIssues in `openspec show --json` output - Report tracked issues when archiving changes - Add External Issue Tracking section to AGENTS.md template - Add TrackedIssue schema and type exports * fix(cli): address PR review feedback and archive external issue tracking - Fix list.ts alignment to include issue display in width calculation - Fix command-name.ts to handle Windows extensions and cross-platform paths - Fix postinstall.js to install completions for both openspec and plx - Fix change.ts issue display format (after title in long format) - Add comprehensive unit tests for all fixes - Archive add-external-issue-tracking change with spec updates --------- Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com>
Summary
openspec listoutput (e.g.,change-name (SM-123) [tasks])trackedIssuesinopenspec show --jsonoutputFrontmatter Format
Test plan
openspec listwith a proposal containing tracked-issues frontmatter - should show issue ID in parenthesesopenspec show <change> --json- should includetrackedIssuesarrayopenspec archive <change>- should report issue IDs in success messageopenspec updatein a project - should include External Issue Tracking section in AGENTS.md