(
repoPath: string
)
| 219 | // Antigravity: ~/.gemini/antigravity/brain/<id>/ |
| 220 | // ------------------------------------------------------------------- |
| 221 | async function extractFromAntigravity( |
| 222 | repoPath: string |
| 223 | ): Promise<ExtractedContext | null> { |
| 224 | const home = os.homedir(); |
| 225 | const brainDir = path.join(home, ".gemini", "antigravity", "brain"); |
| 226 | |
| 227 | if (!fs.existsSync(brainDir)) return null; |
| 228 | |
| 229 | // Find most recent conversation that has artifacts |
| 230 | const conversations = fs |
| 231 | .readdirSync(brainDir) |
| 232 | .map((d) => { |
| 233 | const dir = path.join(brainDir, d); |
| 234 | const taskFile = path.join(dir, "task.md"); |
| 235 | try { |
| 236 | const stat = fs.existsSync(taskFile) |
| 237 | ? fs.statSync(taskFile) |
| 238 | : fs.statSync(dir); |
| 239 | return { name: d, dir, taskFile, mtime: stat.mtime.getTime(), valid: true }; |
| 240 | } catch { |
| 241 | return { name: d, dir, taskFile, mtime: 0, valid: false }; |
| 242 | } |
| 243 | }) |
| 244 | .filter((d) => d.valid && fs.existsSync(d.taskFile)) |
| 245 | .sort((a, b) => b.mtime - a.mtime); |
| 246 | |
| 247 | if (conversations.length === 0) return null; |
| 248 | |
| 249 | const latest = conversations[0]; |
| 250 | |
| 251 | // 1. Try to get the USER'S INTENT from implementation_plan.md |
| 252 | // The plan title and overview section capture what the user wanted |
| 253 | let task = ""; |
| 254 | const decisions: string[] = []; |
| 255 | const approaches: string[] = []; |
| 256 | const planFile = path.join(latest.dir, "implementation_plan.md"); |
| 257 | if (fs.existsSync(planFile)) { |
| 258 | const plan = fs.readFileSync(planFile, "utf-8"); |
| 259 | |
| 260 | // First heading is the goal/intent |
| 261 | const titleMatch = plan.match(/^#\s+(.+)$/m); |
| 262 | if (titleMatch) { |
| 263 | task = titleMatch[1].trim(); |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | // 2. Parse task.md for MORE SPECIFIC active task |
| 268 | // If we have a specific checklist item that is In Progress or Recently Done, use that as the main task |
| 269 | const taskContent = fs.existsSync(latest.taskFile) ? fs.readFileSync(latest.taskFile, "utf-8") : ""; |
| 270 | if (taskContent) { |
| 271 | // Look for in-progress items first (user specific notations like [-] or [/]) |
| 272 | const inProgressMatch = taskContent.match(/-\s+\[[/-]\]\s+(.+)$/m); |
| 273 | if (inProgressMatch) { |
| 274 | task = inProgressMatch[1].trim(); |
| 275 | } else { |
| 276 | // Look for last completed item (likely what was just finished) |
| 277 | const completedMatches = [...taskContent.matchAll(/-\s+\[x\]\s+(.+)$/gm)]; |
| 278 | if (completedMatches.length > 0) { |
nothing calls this directly
no test coverage detected