@@ -9,6 +9,7 @@ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
99import fs from 'node:fs' ;
1010import path from 'node:path' ;
1111import os from 'node:os' ;
12+ import Database from 'better-sqlite3' ;
1213import {
1314 OverviewCache ,
1415 parseStatusYaml ,
@@ -100,6 +101,19 @@ function issueItem(number: number, title: string, labels: Array<{ name: string }
100101 return { number, title, url : `https://github.com/org/repo/issues/${ number } ` , labels, createdAt : '2026-01-01T00:00:00Z' } ;
101102}
102103
104+ /** Create a state.db in the workspace's .agent-farm/ with builder issue_number rows. */
105+ function createStateDb ( root : string , rows : Array < { worktree : string ; issue_number : number } > ) : void {
106+ const agentFarmDir = path . join ( root , '.agent-farm' ) ;
107+ fs . mkdirSync ( agentFarmDir , { recursive : true } ) ;
108+ const db = new Database ( path . join ( agentFarmDir , 'state.db' ) ) ;
109+ db . exec ( 'CREATE TABLE IF NOT EXISTS builders (worktree TEXT, issue_number INTEGER)' ) ;
110+ const insert = db . prepare ( 'INSERT INTO builders (worktree, issue_number) VALUES (?, ?)' ) ;
111+ for ( const row of rows ) {
112+ insert . run ( row . worktree , row . issue_number ) ;
113+ }
114+ db . close ( ) ;
115+ }
116+
103117// ============================================================================
104118// Tests
105119// ============================================================================
@@ -1724,5 +1738,56 @@ describe('overview', () => {
17241738 expect ( data . recentlyClosed ) . toHaveLength ( 1 ) ;
17251739 expect ( data . recentlyClosed [ 0 ] . prUrl ) . toBeUndefined ( ) ;
17261740 } ) ;
1741+
1742+ it ( 'enriches issueId from DB issue_number for unknown protocols (#664)' , async ( ) => {
1743+ // research-533 doesn't match any protocol regex → soft mode, issueId null
1744+ const worktreePath = createBuilderWorktree ( tmpDir , 'research-533-context-window' ) ;
1745+
1746+ // Create a real DB with issue_number for this worktree
1747+ createStateDb ( tmpDir , [ { worktree : worktreePath , issue_number : 533 } ] ) ;
1748+
1749+ const cache = new OverviewCache ( ) ;
1750+ const data = await cache . getOverview ( tmpDir ) ;
1751+
1752+ expect ( data . builders ) . toHaveLength ( 1 ) ;
1753+ expect ( data . builders [ 0 ] . issueId ) . toBe ( '533' ) ;
1754+ } ) ;
1755+
1756+ it ( 'DB issue_number overrides regex-parsed issueId (#664)' , async ( ) => {
1757+ // spir-42 matches the regex → issueId '42' from regex
1758+ // DB also has issue_number 42 → should still be '42'
1759+ const worktreePath = createBuilderWorktree ( tmpDir , 'spir-42-feature' , [
1760+ "id: '0042'" ,
1761+ 'title: feature' ,
1762+ 'protocol: spir' ,
1763+ 'phase: implement' ,
1764+ 'gates:' ,
1765+ ] . join ( '\n' ) , '0042-feature' ) ;
1766+
1767+ createStateDb ( tmpDir , [ { worktree : worktreePath , issue_number : 42 } ] ) ;
1768+
1769+ const cache = new OverviewCache ( ) ;
1770+ const data = await cache . getOverview ( tmpDir ) ;
1771+
1772+ expect ( data . builders ) . toHaveLength ( 1 ) ;
1773+ expect ( data . builders [ 0 ] . issueId ) . toBe ( '42' ) ;
1774+ } ) ;
1775+
1776+ it ( 'falls back to regex-parsed issueId when DB has no issue_number (#664)' , async ( ) => {
1777+ createBuilderWorktree ( tmpDir , 'spir-42-feature' , [
1778+ "id: '0042'" ,
1779+ 'title: feature' ,
1780+ 'protocol: spir' ,
1781+ 'phase: implement' ,
1782+ 'gates:' ,
1783+ ] . join ( '\n' ) , '0042-feature' ) ;
1784+
1785+ // No state.db → regex-parsed issueId preserved
1786+ const cache = new OverviewCache ( ) ;
1787+ const data = await cache . getOverview ( tmpDir ) ;
1788+
1789+ expect ( data . builders ) . toHaveLength ( 1 ) ;
1790+ expect ( data . builders [ 0 ] . issueId ) . toBe ( '42' ) ;
1791+ } ) ;
17271792 } ) ;
17281793} ) ;
0 commit comments