mirror of
https://github.com/Fission-AI/OpenSpec.git
synced 2026-09-14 20:16:53 +08:00
fix/tasks-missing-checkboxes
13 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0296401b82 |
fix(init): add .gitkeep files to empty directories (#786)
* fix(init): add .gitkeep files to empty directories After running openspec init, the specs/, changes/, and changes/archive/ directories are empty. Since git does not track empty directories, these folders are lost when the repository is cloned, causing openspec list to recommend re-initialization. Added .gitkeep file creation to createDirectoryStructure() for both normal and extend modes, ensuring empty directories are preserved in version control. Fixes #269 * fix(init): preserve directory anchors without overwriting user files --------- Co-authored-by: Clay Good <hi@claygood.com> |
||
|
|
cdd06a0594 |
docs(specs): align four requirements with current behavior (#1707)
* docs(openspec): correct 4 requirements that the code has outgrown - ai-tool-paths/path-configuration-for-supported-tools#2: Changed the windsurf scenario's required skillsDir from `.windsurf` to `.devin`. - cli-update/slash-command-updates#6: Require $ARGUMENTS to be placed in the file body (not frontmatter) for OpenCode archive commands. - rules-injection/validate-artifact-ids-during-instruction-loading#6: Updated the expected warning text to use double quotes and to state it matches no artifact in any available schema, listing known artifact IDs. - specs-sync-skill/skill-output#3: Changed the expected no-changes message to 'Specs already in sync; no files changed.' to match the code. None of these reduce what a requirement demands. Scanned at |
||
|
|
c747ed1f34 |
feat(init): add language option (#1685)
* feat(init): add language option * fix(init): harden language configuration * fix(init): fail when language config cannot be written |
||
|
|
f3aa167d6e |
feat(tools): add Zed Agent support (#1659)
* feat(tools): add Zed Agent support * fix(tools): detect Zed projects |
||
|
|
161f9454a3 |
feat: add MiniMax Code skills support (#1214)
* feat: add MiniMax Code skills support to OpenSpec * fix: separate init skill and command output summaries * feat(minimax): add global skills support --------- Co-authored-by: showms <showms@users.noreply.github.com> Co-authored-by: Clay Good <hi@claygood.com> |
||
|
|
2b3d368539 |
fix(archive): tell the caller which flag to pass when archive can't ask its questions (#1483)
* fix(archive): name the flag when a prompt has no terminal to answer it An AI agent runs the CLI with stdin closed, so every confirmation `openspec archive` asks rejects with @inquirer's "User force closed the prompt with 0 null" - true, and useless: it names neither the question nor the flag that answers it, so agents abort and guess (#1479). Each confirmation now reports the same guidance JSON mode has always given for that decision point, with a pasteable command. The change picker got the opposite treatment: it swallowed the same failure, printed "No change selected. Aborting." and exited 0, reporting success for a run that archived nothing. It now exits 1 asking for a change name, matching `openspec show` and `openspec validate`. The detection is reactive - a prompt that already failed, at a stdin that is not a terminal - so piped answers, --yes, --json and Ctrl-C at a real terminal are untouched. Closes #1479 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(archive): carry the caller's flags into the suggested rerun, and honor every non-interactive signal Adversarial review of the first commit found four defects in it: - The suggested rerun dropped the flags the caller had passed. For `archive x --skip-specs` it suggested a bare `--yes` rerun, and following it merged deltas into the main specs - the exact thing --skip-specs was passed to prevent. - The change name went into that command unquoted, so a change named `my change` produced an unrunnable paste and one named `a;touch x` produced a paste that runs a second command. - The predicate keyed on stdin.isTTY alone, so a CI runner that allocates a pty still got the raw @inquirer failure - #1479 unfixed under the very signals `isInteractive()` already treats as authoritative. - A genuine Ctrl-C reaches a process whose stdin is a pipe, and that was reported as "this terminal is not interactive", telling a user who deliberately quit to rerun with --yes. The signal is now `!isInteractive()` with SIGINT excluded, so the terminal proves capability and the signal proves intent. Messages say what happened ("no answer could be read from stdin") rather than asserting a property of the terminal, which was false under MinTTY. Mutation testing found four more gaps in the tests: an unconditional `throw blocked()`, a stripped `withStoreFlag`, and either half of the predicate's `||` all left the suite green. Each now has a test, along with the flag carry-forward, the quoting, the pty-CI case, and the two prompts that had no end-to-end coverage. docs/cli.md documents the behavior without a terminal. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(archive): close two gaps CodeRabbit found in the new guards The template guard required a space after `openspec archive`, so a regression to a bare `openspec archive` line - which blocks agents exactly as #1479 describes - would have passed it. Verified by mutation: the widened pattern fails on that edit. Expected filesystem paths in the new e2e assertions are built from path segments, per the repo's testing guideline. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(archive): make the suggested rerun runnable for dashed names, stores, and Windows shells A second adversarial pass, scoped to the previous two commits, found three defects in the fix itself: - A change named `--force` was emitted bare, and commander reads it as an option however it is quoted, so the suggested command failed with `unknown option`. Such changes do archive, so the case is reachable: the name now goes behind a `--`, with the store flag kept in front of it where it is still read as an option. - The change-name-required path was the one blocked site left hard-coded, so `archive --skip-specs` with nothing to answer the picker suggested a rerun without `--skip-specs` - the same merge the previous commit set out to prevent. - Quoting was POSIX-only: cmd.exe does not treat `'` as quoting at all, and PowerShell escapes an embedded quote by doubling it, so the emitted command was wrong on Windows. Names now use double quotes, which bash, zsh, PowerShell and cmd.exe all read the same way, and a name containing something with no portable spelling (a quote, backslash, `$`, backtick, newline) names the placeholder rather than emitting a command that could expand. Two tests were pinning less than they claimed. The real-terminal cancellation test had become a duplicate of the piped one, since the SIGINT check short-circuits before the terminal is consulted; it now covers the terminal leg with a non-SIGINT failure, which is the leg nothing else guarded. The template guard iterated two identical strings and could not see an indented invocation; it now sweeps every rendered skill and command template, and both mutations were confirmed to fail it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(changeset): name the quoting form the fix actually emits Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(archive): stop quoting change names cmd.exe would expand anyway `%USERNAME%` is a legal change directory name, and cmd.exe expands it inside double quotes, so the suggested rerun `openspec archive "%USERNAME%" --yes` targets a different change than the one that was blocked. `!` has the same problem under cmd.exe's delayed expansion and bash's interactive history expansion. Both characters now fall back to the `<change-name>` placeholder, the same path a `$`/backtick name already took: a rerun the reader has to fill in beats one that silently archives something else. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(archive): stop a change directory from forging its own Fix line Four adversarial reviews of this branch turned up one real defect and two guards that were not actually pinned. The human-mode message for an unanswerable incomplete-task confirmation interpolated the change name raw, and archive resolves a change by stat-ing its directory, so the name is attacker-influenceable. A newline in it added a second, forged `Fix:` line - and because `quoteChangeName` degrades the real fix to `<change-name>` for exactly those names, the forged line was the only pasteable command on screen. Control characters are now collapsed. Also pinned two mutations that passed the whole suite green: dropping `withStoreFlag` from only the dash-leading branch of `rerunCommand`, and dropping the `validate === false` leg of the `--no-validate` test - the one leg Commander actually produces. The --yes parity guard only saw invocations that opened a line, so a `$ ` prompt, a list marker or `openspec --store x archive` slipped past it. It now matches those and names the onboarding floor instead of trusting `total > 0`. Docs and spec catch up: a troubleshooting entry under the message people actually search for, and cli-archive scenarios for the unanswerable-prompt paths, including that Ctrl-C stays a cancellation. * test(archive): tokenise the --yes guard instead of pattern-matching it Accepting a global flag between `openspec` and `archive` needed nested quantifiers, and CodeQL was right to call that a ReDoS shape (js/redos, high) even in a test over our own templates. Splitting the line into tokens decides the same question in linear time - a 20k-flag line now costs ~2ms - and reads more plainly than the pattern did. Same classifications as before, plus it correctly ignores `openspec list archive`, where `archive` is an argument rather than the subcommand. * test(archive): skip the forged-Fix-line case on Windows Windows rejects control characters in a filename, so the change directory the test needs cannot be created there - which is also why the hole it covers is POSIX-only. Matches the existing `it.skipIf(process.platform === 'win32')` idiom in the suite. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
1aa0f2abfc |
feat(init): add shared agents skills target (#1303)
Co-authored-by: Clay Good <hi@claygood.com> |
||
|
|
0ca74762dc | fix windows workspace data dir paths (#1038) | ||
|
|
a18d992fa1 |
fix: suppress ora spinner output when --json flag is used (#960)
When --json is passed, ora spinners wrote progress text to stderr, which broke JSON parsing for AI agents that combine stdout+stderr. Conditionally skip spinner creation in status, instructions, and templates commands. Closes #957 |
||
|
|
39bebefcc4 |
feat(cli): merge init and experimental commands (#565)
* feat(core): add legacy cleanup detection functions for init migration Implement src/core/legacy-cleanup.ts with detection and cleanup functions for all legacy OpenSpec artifact types: Detection functions: - detectLegacyConfigFiles() - checks for config files with OpenSpec markers (CLAUDE.md, CLINE.md, CODEBUDDY.md, COSTRICT.md, QODER.md, IFLOW.md, AGENTS.md, QWEN.md) - detectLegacySlashCommands() - checks for old /openspec:* command directories and files across all 21 tool integrations - detectLegacyStructureFiles() - checks for openspec/AGENTS.md and openspec/project.md (project.md preserved for migration hint) - detectLegacyArtifacts() - orchestrates all detection Utility functions: - hasOpenSpecMarkers() - checks if content has OpenSpec markers - isOnlyOpenSpecContent() - checks if file is 100% OpenSpec content - removeMarkerBlock() - surgically removes marker blocks from mixed content Cleanup functions: - cleanupLegacyArtifacts() - orchestrates removal with proper edge cases: - Deletes files that are 100% OpenSpec content - Removes marker blocks from files with mixed content - Deletes legacy slash command directories and files - Preserves openspec/project.md (shows migration hint only) Formatting functions: - formatDetectionSummary() - formats what was detected before cleanup - formatCleanupSummary() - formats what was cleaned up after This is task 1.1 for the merge-init-experimental change. * feat(utils): add removeMarkerBlock() for surgically removing marker blocks - Add removeMarkerBlock() function to file-system.ts that properly handles inline marker mentions by using findMarkerIndex/isMarkerOnOwnLine - Refactor legacy-cleanup.ts to use the shared utility - Export removeMarkerBlock from utils/index.ts for reusability - Add comprehensive tests for inline marker mention edge cases - Add tests for shell-style markers and various whitespace scenarios The new implementation correctly ignores markers mentioned inline within text and only removes actual marker blocks that are on their own lines. * feat(core): add formatProjectMdMigrationHint() for migration messaging - Add standalone formatProjectMdMigrationHint() function for reusable migration hint output directing users to migrate project.md content to config.yaml's "context:" field - Update formatDetectionSummary() to include the migration hint when project.md is detected (not just in cleanup summary) - Refactor formatCleanupSummary() to use the new function for consistency - Add unit tests for the new function and updated behavior * test(init): rewrite init tests for experimental workflow approach Rewrites the init command tests to verify the new experimental workflow implementation. The new tests cover: - OpenSpec directory structure creation (specs, changes, archive) - config.yaml generation with default schema - 9 Agent Skills creation for various tools (Claude, Cursor, Windsurf, etc.) - 9 slash commands generation using tool-specific adapters - Multi-tool support (--tools all, --tools none, specific tools) - Extend mode (re-running init) - Tool-specific adapters (Gemini TOML, Continue .prompt, etc.) - Error handling for invalid tools and permissions Removes old tests for legacy config file generation (AGENTS.md, CLAUDE.md, project.md, etc.) as the new init command uses Agent Skills instead. * test(update): rewrite tests for skills/commands refresh behavior Update the update command tests to match the new implementation that refreshes skills and opsx commands instead of config files. Changes: - Remove old ToolRegistry import (deleted module) - Rewrite tests to verify skill file updates - Rewrite tests to verify opsx command generation - Add tests for multi-tool support (Claude, Cursor, Qwen, Windsurf) - Add tests for error handling and tool detection - Fix test assertions to match actual skill template names The update command now: - Detects configured tools by checking skill directories - Updates SKILL.md files with latest skill templates - Generates opsx commands using tool-specific adapters * docs(readme): update documentation for new init behavior - Replace tool list with simplified supported tools section (skills-based) - Update init instructions to document --tools flag, --force, and legacy cleanup - Replace project.md with config.yaml documentation - Update workflow examples to use /opsx:* commands instead of /openspec:* - Add command reference table for slash commands - Update Team Adoption and Updating sections for new workflow - Replace Experimental Features with Workflow Customization section * refactor(cli): remove legacy configurators and merge experimental into workflow - Delete src/core/configurators/ directory (ToolRegistry, all config generators) - Delete legacy templates (agents-template, claude-template, project-template, etc.) - Move experimental commands to src/commands/workflow/ with cleaner structure - Remove experimental setup.ts and index.ts (functionality merged into init) - Update CLI to register workflow commands directly instead of through experimental - Update openspec update command to refresh skills/commands instead of config files - Update tests for new command structure * refactor: extract shared modules and move AGENTS.md to root - Move AGENTS.md from openspec/ to project root - Add shared module with tool-detection and skill-generation utilities - Update legacy-cleanup with improved cleanup logic - Enhance update.ts with additional functionality - Add comprehensive tests for shared modules * fix(ui): update welcome screen tagline Change from experimental reference to reflect the merged workflow. * fix: improve Windows cross-platform compatibility - Handle both forward and backward slashes in path parsing - Normalize paths before regex matching for legacy artifact detection - Use regex split for both path separators in tool directory extraction - Handle CRLF line endings when cleaning up multiple blank lines - Add retry logic for test file cleanup to handle Windows file locking * fix(init): use dynamic counts for skills and commands in success message Replace hard-coded "9 skills and 9 commands" with dynamic values from getSkillTemplates().length and getCommandContents().length to prevent the message from diverging from reality when skills/commands change. * fix: various small improvements across init, cleanup, and file handling - Remove shell prompt characters from README bash examples (MD014) - Show actual config filename (config.yaml vs config.yml) in init output - Include hasProjectMd in hasLegacyArtifacts to show migration hint - Add existence check before AGENTS.md deletion to avoid spurious errors - Preserve leading whitespace and original newline style in file operations - Use dynamic tool list from CommandAdapterRegistry in tests |
||
|
|
b81fa1e6cc |
feat: add factory function support for slash commands (#178)
This change adds support for factory functions in slash command configuration, allowing slash commands to be defined as functions that return command objects. |
||
|
|
cc9d5402ff |
feat: add non-interactive options to openspec init (#122)
* feat: add non-interactive options to openspec init - Add --tools, --all-tools, and --skip-tools CLI options - Enable automated initialization for CI/CD pipelines - Maintain backward compatibility with interactive mode - Add comprehensive validation and error handling - Update cli-init spec with non-interactive requirements - Add unit and integration tests for new functionality Closes change proposal: add-non-interactive-init-options * feat(init): add single --tools flag for non-interactive init * test(init): verify --tools help lists available ids * Revert manual spec.md edits The canonical spec shouldn't be edited directly when a change delta already captures the update. Archiving that delta will sync the spec. --------- Co-authored-by: Tabish Bidiwale <30385142+TabishB@users.noreply.github.com> Co-authored-by: Tabish Bidiwale <tabishbidiwale@gmail.com> |
||
|
|
4867bfade5 |
feat: implement Phase 1 E2E testing with cross-platform CI matrix (#80)
* feat: implement Phase 1 E2E testing with cross-platform CI matrix - Add shared runCLI helper in test/helpers/run-cli.ts for spawn testing - Create test/cli-e2e/basic.test.ts covering help, version, validate flows - Migrate existing CLI exec tests to use runCLI helper - Extend CI matrix to bash (Linux/macOS) and pwsh (Windows) - Update Phase 1 tasks and proposal with implementation status * fix: correct YAML syntax in CI workflow diagnostics command * fix: use multiline YAML for diagnostics command * fix ci * fix: ci * fix: update core validation and json converter * chore(ci): split pr and main workflows * refactor: simplify CI workflow with unified matrix strategy - Consolidate test_pr and test_matrix into single test job - Add proper shell configuration with defaults - Add timeout protection (15 minutes) - Simplify required-checks to single job - Maintain cross-platform testing (bash on Linux/macOS, pwsh on Windows) * fix: restore lean PR workflow with async main branch matrix - PRs run only essential tests on ubuntu-latest (fast feedback) - Main branch runs full cross-platform matrix asynchronously - Separate required-checks for each workflow type - Different timeouts: 10min for PR, 15min for matrix |