mirror of
https://github.com/Fission-AI/OpenSpec.git
synced 2026-10-02 05:24:34 +08:00
Merge branch 'main' into TabishB/west-monroe
This commit is contained in:
@@ -26,7 +26,7 @@ import {
|
||||
type ArtifactInstructions,
|
||||
} from '../core/artifact-graph/index.js';
|
||||
import { createChange, validateChangeName } from '../utils/change-utils.js';
|
||||
import { getNewChangeSkillTemplate, getContinueChangeSkillTemplate, getApplyChangeSkillTemplate } from '../core/templates/skill-templates.js';
|
||||
import { getNewChangeSkillTemplate, getContinueChangeSkillTemplate, getApplyChangeSkillTemplate, getOpsxNewCommandTemplate, getOpsxContinueCommandTemplate, getOpsxApplyCommandTemplate } from '../core/templates/skill-templates.js';
|
||||
import { FileSystemUtils } from '../utils/file-system.js';
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -701,21 +701,28 @@ async function newChangeCommand(name: string | undefined, options: NewChangeOpti
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Generates Agent Skills for the experimental artifact workflow.
|
||||
* Generates Agent Skills and slash commands for the experimental artifact workflow.
|
||||
* Creates .claude/skills/ directory with SKILL.md files following Agent Skills spec.
|
||||
* Creates .claude/commands/opsx/ directory with slash command files.
|
||||
*/
|
||||
async function artifactExperimentalSetupCommand(): Promise<void> {
|
||||
const spinner = ora('Setting up experimental artifact workflow skills...').start();
|
||||
const spinner = ora('Setting up experimental artifact workflow...').start();
|
||||
|
||||
try {
|
||||
const projectRoot = process.cwd();
|
||||
const skillsDir = path.join(projectRoot, '.claude', 'skills');
|
||||
const commandsDir = path.join(projectRoot, '.claude', 'commands', 'opsx');
|
||||
|
||||
// Get skill templates
|
||||
const newChangeSkill = getNewChangeSkillTemplate();
|
||||
const continueChangeSkill = getContinueChangeSkillTemplate();
|
||||
const applyChangeSkill = getApplyChangeSkillTemplate();
|
||||
|
||||
// Get command templates
|
||||
const newCommand = getOpsxNewCommandTemplate();
|
||||
const continueCommand = getOpsxContinueCommandTemplate();
|
||||
const applyCommand = getOpsxApplyCommandTemplate();
|
||||
|
||||
// Create skill directories and SKILL.md files
|
||||
const skills = [
|
||||
{ template: newChangeSkill, dirName: 'openspec-new-change' },
|
||||
@@ -723,7 +730,7 @@ async function artifactExperimentalSetupCommand(): Promise<void> {
|
||||
{ template: applyChangeSkill, dirName: 'openspec-apply-change' },
|
||||
];
|
||||
|
||||
const createdFiles: string[] = [];
|
||||
const createdSkillFiles: string[] = [];
|
||||
|
||||
for (const { template, dirName } of skills) {
|
||||
const skillDir = path.join(skillsDir, dirName);
|
||||
@@ -740,31 +747,69 @@ ${template.instructions}
|
||||
|
||||
// Write the skill file
|
||||
await FileSystemUtils.writeFile(skillFile, skillContent);
|
||||
createdFiles.push(path.relative(projectRoot, skillFile));
|
||||
createdSkillFiles.push(path.relative(projectRoot, skillFile));
|
||||
}
|
||||
|
||||
// Create slash command files
|
||||
const commands = [
|
||||
{ template: newCommand, fileName: 'new.md' },
|
||||
{ template: continueCommand, fileName: 'continue.md' },
|
||||
{ template: applyCommand, fileName: 'apply.md' },
|
||||
];
|
||||
|
||||
const createdCommandFiles: string[] = [];
|
||||
|
||||
for (const { template, fileName } of commands) {
|
||||
const commandFile = path.join(commandsDir, fileName);
|
||||
|
||||
// Generate command content with YAML frontmatter
|
||||
const commandContent = `---
|
||||
name: ${template.name}
|
||||
description: ${template.description}
|
||||
category: ${template.category}
|
||||
tags: [${template.tags.join(', ')}]
|
||||
---
|
||||
|
||||
${template.content}
|
||||
`;
|
||||
|
||||
// Write the command file
|
||||
await FileSystemUtils.writeFile(commandFile, commandContent);
|
||||
createdCommandFiles.push(path.relative(projectRoot, commandFile));
|
||||
}
|
||||
|
||||
spinner.succeed('Experimental artifact workflow setup complete!');
|
||||
|
||||
// Print success message
|
||||
console.log();
|
||||
console.log(chalk.bold('🧪 Experimental Artifact Workflow Skills Created'));
|
||||
console.log(chalk.bold('🧪 Experimental Artifact Workflow Setup Complete'));
|
||||
console.log();
|
||||
for (const file of createdFiles) {
|
||||
console.log(chalk.bold('Skills Created:'));
|
||||
for (const file of createdSkillFiles) {
|
||||
console.log(chalk.green(' ✓ ' + file));
|
||||
}
|
||||
console.log();
|
||||
console.log(chalk.bold('Slash Commands Created:'));
|
||||
for (const file of createdCommandFiles) {
|
||||
console.log(chalk.green(' ✓ ' + file));
|
||||
}
|
||||
console.log();
|
||||
console.log(chalk.bold('📖 Usage:'));
|
||||
console.log();
|
||||
console.log(' Skills work automatically in compatible editors:');
|
||||
console.log(' • ' + chalk.cyan('Claude Code') + ' - Auto-detected, ready to use');
|
||||
console.log(' • ' + chalk.cyan('Cursor') + ' - Enable in Settings → Rules → Import Settings');
|
||||
console.log(' • ' + chalk.cyan('Windsurf') + ' - Auto-imports from .claude directory');
|
||||
console.log(' ' + chalk.cyan('Skills') + ' work automatically in compatible editors:');
|
||||
console.log(' • Claude Code - Auto-detected, ready to use');
|
||||
console.log(' • Cursor - Enable in Settings → Rules → Import Settings');
|
||||
console.log(' • Windsurf - Auto-imports from .claude directory');
|
||||
console.log();
|
||||
console.log(' Ask Claude naturally:');
|
||||
console.log(' • "I want to start a new OpenSpec change to add <feature>"');
|
||||
console.log(' • "Continue working on this change"');
|
||||
console.log(' • "Implement the tasks for this change"');
|
||||
console.log();
|
||||
console.log(' Claude will automatically use the appropriate skill.');
|
||||
console.log(' ' + chalk.cyan('Slash Commands') + ' for explicit invocation:');
|
||||
console.log(' • /opsx:new - Start a new change');
|
||||
console.log(' • /opsx:continue - Create the next artifact');
|
||||
console.log(' • /opsx:apply - Implement tasks');
|
||||
console.log();
|
||||
console.log(chalk.yellow('💡 This is an experimental feature.'));
|
||||
console.log(' Feedback welcome at: https://github.com/Fission-AI/OpenSpec/issues');
|
||||
|
||||
@@ -319,3 +319,324 @@ This skill supports the "actions on a change" model:
|
||||
- **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly`
|
||||
};
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Slash Command Templates
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
export interface CommandTemplate {
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
tags: string[];
|
||||
content: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template for /opsx:new slash command
|
||||
*/
|
||||
export function getOpsxNewCommandTemplate(): CommandTemplate {
|
||||
return {
|
||||
name: 'OPSX: New',
|
||||
description: 'Start a new change using the experimental artifact workflow (OPSX)',
|
||||
category: 'Workflow',
|
||||
tags: ['workflow', 'artifacts', 'experimental'],
|
||||
content: `Start a new change using the experimental artifact-driven approach.
|
||||
|
||||
**Input**: The argument after \`/opsx:new\` is the change name (kebab-case), OR a description of what the user wants to build.
|
||||
|
||||
**Steps**
|
||||
|
||||
1. **If no input provided, ask what they want to build**
|
||||
|
||||
Use the **AskUserQuestion tool** (open-ended, no preset options) to ask:
|
||||
> "What change do you want to work on? Describe what you want to build or fix."
|
||||
|
||||
From their description, derive a kebab-case name (e.g., "add user authentication" → \`add-user-auth\`).
|
||||
|
||||
**IMPORTANT**: Do NOT proceed without understanding what the user wants to build.
|
||||
|
||||
2. **Create the change directory**
|
||||
\`\`\`bash
|
||||
openspec new change "<name>"
|
||||
\`\`\`
|
||||
This creates a scaffolded change at \`openspec/changes/<name>/\`.
|
||||
|
||||
3. **Show the artifact status**
|
||||
\`\`\`bash
|
||||
openspec status --change "<name>"
|
||||
\`\`\`
|
||||
This shows which artifacts need to be created and which are ready (dependencies satisfied).
|
||||
|
||||
4. **Get instructions for the first artifact**
|
||||
The first artifact is always \`proposal\` (no dependencies).
|
||||
\`\`\`bash
|
||||
openspec instructions proposal --change "<name>"
|
||||
\`\`\`
|
||||
This outputs the template and context for creating the proposal.
|
||||
|
||||
5. **STOP and wait for user direction**
|
||||
|
||||
**Output**
|
||||
|
||||
After completing the steps, summarize:
|
||||
- Change name and location
|
||||
- Current status (0/4 artifacts complete)
|
||||
- The template for the proposal artifact
|
||||
- Prompt: "Ready to create the proposal? Run \`/opsx:continue\` or just describe what this change is about and I'll draft the proposal."
|
||||
|
||||
**Guardrails**
|
||||
- Do NOT create any artifacts yet - just show the instructions
|
||||
- Do NOT advance beyond showing the proposal template
|
||||
- If the name is invalid (not kebab-case), ask for a valid name
|
||||
- If a change with that name already exists, suggest using \`/opsx:continue\` instead`
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Template for /opsx:continue slash command
|
||||
*/
|
||||
export function getOpsxContinueCommandTemplate(): CommandTemplate {
|
||||
return {
|
||||
name: 'OPSX: Continue',
|
||||
description: 'Continue working on a change - create the next artifact (Experimental)',
|
||||
category: 'Workflow',
|
||||
tags: ['workflow', 'artifacts', 'experimental'],
|
||||
content: `Continue working on a change by creating the next artifact.
|
||||
|
||||
**Input**: Optionally specify \`--change <name>\` after \`/opsx:continue\`. If omitted, MUST prompt for available changes.
|
||||
|
||||
**Steps**
|
||||
|
||||
1. **If no change name provided, prompt for selection**
|
||||
|
||||
Run \`openspec list --json\` to get available changes sorted by most recently modified. Then use the **AskUserQuestion tool** to let the user select which change to work on.
|
||||
|
||||
Present the top 3-4 most recently modified changes as options, showing:
|
||||
- Change name
|
||||
- Status (e.g., "0/5 tasks", "complete", "no tasks")
|
||||
- How recently it was modified (from \`lastModified\` field)
|
||||
|
||||
Mark the most recently modified change as "(Recommended)" since it's likely what the user wants to continue.
|
||||
|
||||
**IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
|
||||
|
||||
2. **Check current status**
|
||||
\`\`\`bash
|
||||
openspec status --change "<name>" --json
|
||||
\`\`\`
|
||||
Parse the JSON to understand current state.
|
||||
|
||||
3. **Act based on status**:
|
||||
|
||||
---
|
||||
|
||||
**If all artifacts are complete (\`isComplete: true\`)**:
|
||||
- Congratulate the user
|
||||
- Show final status
|
||||
- Suggest: "All artifacts created! You can now implement this change or archive it."
|
||||
- STOP
|
||||
|
||||
---
|
||||
|
||||
**If artifacts are ready to create** (status shows artifacts with \`status: "ready"\`):
|
||||
- Pick the FIRST artifact with \`status: "ready"\` from the status output
|
||||
- Get its instructions:
|
||||
\`\`\`bash
|
||||
openspec instructions <artifact-id> --change "<name>" --json
|
||||
\`\`\`
|
||||
- Parse the JSON to get template, dependencies, and what it unlocks
|
||||
- **Create the artifact file** using the template as a starting point:
|
||||
- Read any completed dependency files for context
|
||||
- Fill in the template based on context and user's goals
|
||||
- Write to the output path specified in instructions
|
||||
- Show what was created and what's now unlocked
|
||||
- STOP after creating ONE artifact
|
||||
|
||||
---
|
||||
|
||||
**If no artifacts are ready (all blocked)**:
|
||||
- This shouldn't happen with a valid schema
|
||||
- Show status and suggest checking for issues
|
||||
|
||||
4. **After creating an artifact, show progress**
|
||||
\`\`\`bash
|
||||
openspec status --change "<name>"
|
||||
\`\`\`
|
||||
|
||||
**Output**
|
||||
|
||||
After each invocation, show:
|
||||
- Which artifact was created
|
||||
- Current progress (N/M complete)
|
||||
- What artifacts are now unlocked
|
||||
- Prompt: "Run \`/opsx:continue\` to create the next artifact"
|
||||
|
||||
**Artifact Creation Guidelines**
|
||||
|
||||
When filling in templates:
|
||||
|
||||
- **proposal.md**: Ask user about the change if not clear. Fill in Why, What Changes, Capabilities, Impact.
|
||||
- **IMPORTANT**: The Capabilities section is critical. Before filling it in:
|
||||
- Check \`openspec/specs/\` for existing capabilities
|
||||
- List new capabilities with kebab-case names (e.g., \`user-auth\`, \`data-export\`)
|
||||
- List modified capabilities that need spec updates
|
||||
- Each capability listed will need a corresponding spec file in the next phase.
|
||||
- **specs/*.md**: Create one spec per capability listed in the proposal. Use \`specs/<capability-name>/spec.md\` path.
|
||||
- **design.md**: Document technical decisions, architecture, and implementation approach.
|
||||
- **tasks.md**: Break down implementation into checkboxed tasks based on specs and design.
|
||||
|
||||
**Guardrails**
|
||||
- Create ONE artifact per invocation
|
||||
- Always read dependency artifacts before creating a new one
|
||||
- Never skip artifacts or create out of order
|
||||
- If context is unclear, ask the user before creating
|
||||
- Verify the artifact file exists after writing before marking progress`
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Template for /opsx:apply slash command
|
||||
*/
|
||||
export function getOpsxApplyCommandTemplate(): CommandTemplate {
|
||||
return {
|
||||
name: 'OPSX: Apply',
|
||||
description: 'Implement tasks from an OpenSpec change (Experimental)',
|
||||
category: 'Workflow',
|
||||
tags: ['workflow', 'artifacts', 'experimental'],
|
||||
content: `Implement tasks from an OpenSpec change.
|
||||
|
||||
**Input**: Optionally specify \`--change <name>\` after \`/opsx:apply\`. If omitted, MUST prompt for available changes.
|
||||
|
||||
**Steps**
|
||||
|
||||
1. **If no change name provided, prompt for selection**
|
||||
|
||||
Run \`openspec list --json\` to get available changes. Use the **AskUserQuestion tool** to let the user select.
|
||||
|
||||
Show changes that have tasks.md (implementation-ready).
|
||||
Mark changes with incomplete tasks as "(In Progress)".
|
||||
|
||||
**IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
|
||||
|
||||
2. **Get apply instructions**
|
||||
|
||||
\`\`\`bash
|
||||
openspec instructions apply --change "<name>" --json
|
||||
\`\`\`
|
||||
|
||||
This returns:
|
||||
- Context file paths (proposal, specs, design, tasks)
|
||||
- Progress (total, complete, remaining)
|
||||
- Task list with status
|
||||
- Dynamic instruction based on current state
|
||||
|
||||
**Handle states:**
|
||||
- If \`state: "blocked"\` (missing artifacts): show message, suggest using \`/opsx:continue\`
|
||||
- If \`state: "all_done"\`: congratulate, suggest archive
|
||||
- Otherwise: proceed to implementation
|
||||
|
||||
3. **Read context files**
|
||||
|
||||
Read the files listed in \`contextFiles\`:
|
||||
- \`proposal\` - why and what
|
||||
- \`specs\` - requirements and scenarios (use glob pattern to find all)
|
||||
- \`design\` - technical approach (if exists)
|
||||
- \`tasks\` - the implementation checklist
|
||||
|
||||
4. **Show current progress**
|
||||
|
||||
Display:
|
||||
- Progress: "N/M tasks complete"
|
||||
- Remaining tasks overview
|
||||
- Dynamic instruction from CLI
|
||||
|
||||
5. **Implement tasks (loop until done or blocked)**
|
||||
|
||||
For each pending task:
|
||||
- Show which task is being worked on
|
||||
- Make the code changes required
|
||||
- Keep changes minimal and focused
|
||||
- Mark task complete in tasks.md: \`- [ ]\` → \`- [x]\`
|
||||
- Continue to next task
|
||||
|
||||
**Pause if:**
|
||||
- Task is unclear → ask for clarification
|
||||
- Implementation reveals a design issue → suggest updating artifacts
|
||||
- Error or blocker encountered → report and wait for guidance
|
||||
- User interrupts
|
||||
|
||||
6. **On completion or pause, show status**
|
||||
|
||||
Display:
|
||||
- Tasks completed this session
|
||||
- Overall progress: "N/M tasks complete"
|
||||
- If all done: suggest archive
|
||||
- If paused: explain why and wait for guidance
|
||||
|
||||
**Output During Implementation**
|
||||
|
||||
\`\`\`
|
||||
## Implementing: <change-name>
|
||||
|
||||
Working on task 3/7: <task description>
|
||||
[...implementation happening...]
|
||||
✓ Task complete
|
||||
|
||||
Working on task 4/7: <task description>
|
||||
[...implementation happening...]
|
||||
✓ Task complete
|
||||
\`\`\`
|
||||
|
||||
**Output On Completion**
|
||||
|
||||
\`\`\`
|
||||
## Implementation Complete
|
||||
|
||||
**Change:** <change-name>
|
||||
**Progress:** 7/7 tasks complete ✓
|
||||
|
||||
### Completed This Session
|
||||
- [x] Task 1
|
||||
- [x] Task 2
|
||||
...
|
||||
|
||||
All tasks complete! Ready to archive this change.
|
||||
\`\`\`
|
||||
|
||||
**Output On Pause (Issue Encountered)**
|
||||
|
||||
\`\`\`
|
||||
## Implementation Paused
|
||||
|
||||
**Change:** <change-name>
|
||||
**Progress:** 4/7 tasks complete
|
||||
|
||||
### Issue Encountered
|
||||
<description of the issue>
|
||||
|
||||
**Options:**
|
||||
1. <option 1>
|
||||
2. <option 2>
|
||||
3. Other approach
|
||||
|
||||
What would you like to do?
|
||||
\`\`\`
|
||||
|
||||
**Guardrails**
|
||||
- Keep going through tasks until done or blocked
|
||||
- Always read context before starting (specs, design)
|
||||
- If task is ambiguous, pause and ask before implementing
|
||||
- If implementation reveals issues, pause and suggest artifact updates
|
||||
- Keep code changes minimal and scoped to each task
|
||||
- Update task checkbox immediately after completing each task
|
||||
- Pause on errors, blockers, or unclear requirements - don't guess
|
||||
|
||||
**Fluid Workflow Integration**
|
||||
|
||||
This skill supports the "actions on a change" model:
|
||||
|
||||
- **Can be invoked anytime**: Before all artifacts are done (if tasks.md exists), after partial implementation, interleaved with other actions
|
||||
- **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly`
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user