Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,24 @@ The pre-commit hook will reject files with CRLF line endings.
| New feature | `.project/features/upcoming/` | Create spec first |
| Complete feature | `.project/features/completed/` | **Follow ceremony** (see below) |

## Interactive Story Workflow

You can work on an Aura story interactively from any Copilot CLI session. Use the `/work-on-story` prompt to bootstrap, or follow this flow manually:

1. **Find your story**: `aura_workflow(operation: "list")` or `aura_workflow(operation: "get", storyId: "...")`
2. **Get next step**: `aura_workflow(operation: "next_step", storyId: "...")` — returns the next actionable step with full context
3. **Start the step**: `aura_workflow(operation: "start_step", storyId: "...", stepId: "...")` — marks it Running
4. **Do the work**: Edit files in the worktree using **absolute paths** from the step context
5. **Complete the step**: `aura_workflow(operation: "update_step", storyId: "...", stepId: "...", status: "completed", output: "...")`
6. **Repeat** until all steps done, then `aura_workflow(operation: "complete", storyId: "...")`

**Critical conventions when working on a story:**
- Your cwd is the main workspace, but **file edits must target the worktree** (absolute paths)
- Use `worktreeSolutionPath` from step context for `aura_validate` calls
- Use `repositoryPath` for `aura_search` — RAG indexes the main repo, not the worktree
- Run git commands with `cd <worktreePath> && git ...`
- Load the full pattern: `aura_pattern(operation: "get", name: "interactive-story")`

## Blast Radius Protocol (Renames, Extract, Large Changes)

`aura_refactor` defaults to **analyze mode** (`analyze: true`). Before executing any refactoring:
Expand Down
4 changes: 2 additions & 2 deletions extension/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 37 additions & 2 deletions extension/src/providers/storyPanelProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3325,6 +3325,16 @@ export class StoryPanelProvider {
}
}

// Track elapsed time timers per step
const stepTimers = {};

function formatElapsed(seconds) {
if (seconds < 60) return seconds + 's';
const m = Math.floor(seconds / 60);
const s = seconds % 60;
return m + 'm ' + s + 's';
}

function showStepStreaming(stepId, stepName) {
const stepCard = document.querySelector('[data-step-id="' + stepId + '"]');
if (!stepCard) return;
Expand All @@ -3333,16 +3343,31 @@ export class StoryPanelProvider {
const existing = stepCard.querySelector('.step-streaming');
if (existing) existing.remove();

// Clear any existing timer for this step
if (stepTimers[stepId]) {
clearInterval(stepTimers[stepId]);
}

// Create streaming output section
const streaming = document.createElement('div');
streaming.className = 'step-streaming';
streaming.id = 'streaming-' + stepId;
streaming.innerHTML = '<div class="step-streaming-header"><div class="spinner"></div>Executing...</div><div class="step-streaming-content" id="streaming-content-' + stepId + '"></div>';
streaming.innerHTML = '<div class="step-streaming-header"><div class="spinner"></div><span class="step-elapsed" id="elapsed-' + stepId + '">Executing... (0s)</span></div><div class="step-streaming-content" id="streaming-content-' + stepId + '"></div>';

// Insert after the header (and progress bar if present)
const header = stepCard.querySelector('.step-header');
const progress = stepCard.querySelector('.step-progress');
(progress || header).after(streaming);

// Start elapsed time counter
const startTime = Date.now();
stepTimers[stepId] = setInterval(() => {
const elapsed = Math.floor((Date.now() - startTime) / 1000);
const el = document.getElementById('elapsed-' + stepId);
if (el) {
el.textContent = 'Executing... (' + formatElapsed(elapsed) + ')';
}
}, 1000);
}

function appendStepOutput(stepId, text, type) {
Expand All @@ -3357,12 +3382,22 @@ export class StoryPanelProvider {
}

function finalizeStepStreaming(stepId, success) {
// Stop the elapsed timer
if (stepTimers[stepId]) {
clearInterval(stepTimers[stepId]);
delete stepTimers[stepId];
}

const streaming = document.getElementById('streaming-' + stepId);
if (!streaming) return;

const header = streaming.querySelector('.step-streaming-header');
if (header) {
header.innerHTML = success ? '✓ Completed' : '✗ Failed';
// Calculate final duration
const elapsedEl = document.getElementById('elapsed-' + stepId);
const durationText = elapsedEl ? elapsedEl.textContent.replace('Executing... ', '') : '';
const statusText = success ? '✓ Completed' : '✗ Failed';
header.innerHTML = statusText + (durationText ? ' ' + durationText : '');
header.style.color = success ? 'var(--vscode-terminal-ansiBrightGreen)' : 'var(--vscode-terminal-ansiBrightRed)';
}
}
Expand Down