MCPcopy
hub / github.com/Fission-AI/OpenSpec / execute

Method execute

src/core/list.ts:80–209  ·  view source on GitHub ↗
(targetPath: string = '.', mode: 'changes' | 'specs' = 'changes', options: ListOptions = {})

Source from the content-addressed store, hash-verified

78
79export class ListCommand {
80 async execute(targetPath: string = '.', mode: 'changes' | 'specs' = 'changes', options: ListOptions = {}): Promise<void> {
81 const { sort = 'recent', json = false, root } = options;
82
83 if (mode === 'changes') {
84 const changesDir = path.join(targetPath, 'openspec', 'changes');
85
86 // Check if changes directory exists
87 try {
88 await fs.access(changesDir);
89 } catch {
90 throw new Error("No OpenSpec changes directory found. Run 'openspec init' first.");
91 }
92
93 // Get all directories in changes (excluding archive)
94 const entries = await fs.readdir(changesDir, { withFileTypes: true });
95 const changeDirs = entries
96 .filter(entry => entry.isDirectory() && entry.name !== 'archive')
97 .map(entry => entry.name);
98
99 if (changeDirs.length === 0) {
100 if (json) {
101 console.log(JSON.stringify({ changes: [], ...(root ? { root } : {}) }, null, 2));
102 } else {
103 console.log('No active changes found.');
104 }
105 return;
106 }
107
108 // Collect information about each change
109 const changes: ChangeInfo[] = [];
110
111 for (const changeDir of changeDirs) {
112 const progress = await getTaskProgressForChange(changesDir, changeDir);
113 const changePath = path.join(changesDir, changeDir);
114 const lastModified = await getLastModified(changePath);
115 changes.push({
116 name: changeDir,
117 completedTasks: progress.completed,
118 totalTasks: progress.total,
119 lastModified
120 });
121 }
122
123 // Sort by preference (default: recent first)
124 if (sort === 'recent') {
125 changes.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
126 } else {
127 changes.sort((a, b) => a.name.localeCompare(b.name));
128 }
129
130 // JSON output for programmatic use
131 if (json) {
132 const jsonOutput = changes.map(c => ({
133 name: c.name,
134 completedTasks: c.completedTasks,
135 totalTasks: c.totalTasks,
136 lastModified: c.lastModified.toISOString(),
137 status: c.totalTasks === 0 ? 'no-tasks' : c.completedTasks === c.totalTasks ? 'complete' : 'in-progress'

Callers

nothing calls this directly

Calls 5

parseSpecMethod · 0.95
getTaskProgressForChangeFunction · 0.85
getLastModifiedFunction · 0.85
formatTaskStatusFunction · 0.85
formatRelativeTimeFunction · 0.85

Tested by

no test coverage detected