feat(FN-2991): merge fusion/fn-2991

Commits merged:
- fix(FN-2991): align failed research status badge semantics
- feat(FN-2991): add research dashboard view and navigation entry
- fix(FN-2991): complete Step 8 — resolve lint and typecheck gates
- test(FN-2991): address review feedback for Step 7
- test(FN-2991): complete Step 7 — add research store and route tests
- feat(FN-2991): complete Step 6 — add research client API helpers
- feat(FN-2991): complete Step 5 — add research REST routes
- feat(FN-2991): complete Step 4 — wire research store into core exports
- feat(FN-2991): complete Step 3 — implement research store
- feat(FN-2991): complete Step 2 — add research schema and migration
- feat(FN-2991): complete Step 1 — add research domain types

Files changed:
packages/core/src/__tests__/db.test.ts             |  26 +-
 packages/core/src/__tests__/insight-store.test.ts  |   8 +-
 packages/core/src/__tests__/mission-store.test.ts  |   2 +-
 packages/core/src/__tests__/research-store.test.ts | 118 +++++++
 packages/core/src/__tests__/roadmap-store.test.ts  |   2 +-
 packages/core/src/__tests__/run-audit.test.ts      |   2 +-
 packages/core/src/__tests__/task-documents.test.ts |   2 +-
 packages/core/src/db.ts                            |  82 ++++-
 packages/core/src/index.ts                         |  30 ++
 packages/core/src/research-store.ts                | 377 +++++++++++++++++++++
 packages/core/src/research-types.ts                | 162 +++++++++
 packages/core/src/store.ts                         |  14 +
 packages/dashboard/app/App.tsx                     |  12 +
 .../app/api/__tests__/research-api.test.ts         | 120 +++++++
 packages/dashboard/app/api/legacy.ts               | 132 +++++++-
 packages/dashboard/app/components/Header.tsx       |  23 +-
 packages/dashboard/app/components/MobileNavBar.tsx |  16 +-
 packages/dashboard/app/components/ResearchView.css | 110 ++++++
 packages/dashboard/app/components/ResearchView.tsx | 145 ++++++++
 .../app/components/__tests__/Header.test.tsx       |   4 +-
 .../app/components/__tests__/ResearchView.test.tsx | 170 ++++++++++
 packages/dashboard/app/hooks/useViewState.ts       |   3 +-
 packages/dashboard/src/research-routes.ts          | 223 ++++++++++++
 .../src/routes/register-integrated-routers.ts      |   2 +
 24 files changed, 1751 insertions(+), 34 deletions(-)

Fusion-Task-Id: FN-2991
This commit is contained in:
Fusion
2026-04-29 22:21:27 -07:00
committed by gsxdsm
parent b78dd3e055
commit c5de7e183b
24 changed files with 1751 additions and 34 deletions

View File

@@ -86,7 +86,7 @@ export function probeFts5(db: DatabaseSync): boolean {
// ── Schema Definition ────────────────────────────────────────────────
const SCHEMA_VERSION = 54;
const SCHEMA_VERSION = 55;
function normalizeTaskComments(
steeringComments: SteeringComment[] | undefined,
@@ -411,6 +411,41 @@ CREATE TABLE IF NOT EXISTS task_document_revisions (
);
CREATE INDEX IF NOT EXISTS idxTaskDocumentRevisionsTaskKey ON task_document_revisions(taskId, key);
-- Research runs persistence (FN-2991)
CREATE TABLE IF NOT EXISTS research_runs (
id TEXT PRIMARY KEY,
query TEXT NOT NULL,
topic TEXT,
status TEXT NOT NULL,
providerConfig TEXT,
sources TEXT NOT NULL DEFAULT '[]',
events TEXT NOT NULL DEFAULT '[]',
results TEXT,
error TEXT,
tokenUsage TEXT,
tags TEXT NOT NULL DEFAULT '[]',
metadata TEXT,
createdAt TEXT NOT NULL,
updatedAt TEXT NOT NULL,
startedAt TEXT,
completedAt TEXT,
cancelledAt TEXT
);
CREATE INDEX IF NOT EXISTS idxResearchRunsStatus ON research_runs(status);
CREATE INDEX IF NOT EXISTS idxResearchRunsCreatedAt ON research_runs(createdAt);
CREATE INDEX IF NOT EXISTS idxResearchRunsUpdatedAt ON research_runs(updatedAt);
CREATE TABLE IF NOT EXISTS research_exports (
id TEXT PRIMARY KEY,
runId TEXT NOT NULL,
format TEXT NOT NULL,
content TEXT NOT NULL,
filePath TEXT,
createdAt TEXT NOT NULL,
FOREIGN KEY (runId) REFERENCES research_runs(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idxResearchExportsRunId ON research_exports(runId);
-- Schema version tracking
CREATE TABLE IF NOT EXISTS __meta (
key TEXT PRIMARY KEY,
@@ -1999,6 +2034,51 @@ export class Database {
});
}
// Research runs + exports persistence tables (FN-2991).
if (version < 55) {
this.applyMigration(55, () => {
this.db.exec(`
CREATE TABLE IF NOT EXISTS research_runs (
id TEXT PRIMARY KEY,
query TEXT NOT NULL,
topic TEXT,
status TEXT NOT NULL,
providerConfig TEXT,
sources TEXT NOT NULL DEFAULT '[]',
events TEXT NOT NULL DEFAULT '[]',
results TEXT,
error TEXT,
tokenUsage TEXT,
tags TEXT NOT NULL DEFAULT '[]',
metadata TEXT,
createdAt TEXT NOT NULL,
updatedAt TEXT NOT NULL,
startedAt TEXT,
completedAt TEXT,
cancelledAt TEXT
)
`);
this.db.exec(`CREATE INDEX IF NOT EXISTS idxResearchRunsStatus ON research_runs(status)`);
this.db.exec(`CREATE INDEX IF NOT EXISTS idxResearchRunsCreatedAt ON research_runs(createdAt)`);
this.db.exec(`CREATE INDEX IF NOT EXISTS idxResearchRunsUpdatedAt ON research_runs(updatedAt)`);
this.db.exec(`
CREATE TABLE IF NOT EXISTS research_exports (
id TEXT PRIMARY KEY,
runId TEXT NOT NULL,
format TEXT NOT NULL,
content TEXT NOT NULL,
filePath TEXT,
createdAt TEXT NOT NULL,
FOREIGN KEY (runId) REFERENCES research_runs(id) ON DELETE CASCADE
)
`);
this.db.exec(`CREATE INDEX IF NOT EXISTS idxResearchExportsRunId ON research_exports(runId)`);
});
}
}
/**