feat: let agents read supervisor story graphs

Expose saved decisions, timelines and source evidence through read-only Story Graph tools across Model, Harness and local/remote OpenCode and Continue. Supervisor enablement and runtime assignments govern discovery and calls; reads do not invoke models or modify stored evidence. Remote use requires matching Desktop and Agent changes.

Make Continue discussion show the complete editable message with a separated destination and shared action layout. Sending uses the visible draft without reattaching removed context.

Validation: existing focused MCP, runtime, controlled Linux Host, discussion component and Electron layout checks plus typechecks; staged diff check passed. Cross-scope fact reuse, historical reconstruction and full package acceptance remain deferred.

Release note: Agents can consult saved supervisor decisions and their sources when continuing work. Continue discussion now lets you review and edit the complete message before sending.
This commit is contained in:
mesalogo
2026-09-28 12:38:00 +08:00
parent 83a3ea261e
commit 66f77b83c2
61 changed files with 1527 additions and 150 deletions
@@ -165,6 +165,7 @@ describe('CapabilityService', () => {
const stored = JSON.parse(await readFile(filePath, 'utf8'))
delete stored.obsidian
delete stored.builtinMcpServers.obsidian
delete stored.builtinMcpServers['story-graph']
stored.version = version
if (version === 5) delete stored.builtinMcpServers['builtin-browser']
if (version === 1) {
@@ -322,6 +323,7 @@ describe('CapabilityService', () => {
await expect(service.getSnapshot()).resolves.toMatchObject({
builtinMcpServers: [
{ id: 'story-graph', enabled: true, assignments: ['model', 'opencode', 'continue', 'deepseek-harness'] },
{
id: 'knowledge-base',
enabled: true,
@@ -366,19 +368,23 @@ describe('CapabilityService', () => {
await expect(
service.getEnabledBuiltinMcpServerIds('model')
).resolves.toEqual(['knowledge-base', 'goodbuddy-config'])
).resolves.toEqual(['story-graph', 'knowledge-base', 'goodbuddy-config'])
await expect(
service.getEnabledBuiltinMcpServerIds('opencode')
).resolves.toEqual(['goodbuddy-config'])
).resolves.toEqual(['story-graph', 'goodbuddy-config'])
await expect(
service.getEnabledBuiltinMcpServerIds('continue')
).resolves.toEqual([
'story-graph',
'goodbuddy-config',
'builtin-browser'
])
await expect(
service.getEnabledBuiltinMcpServerIds('deepseek-harness')
).resolves.toEqual([])
).resolves.toEqual(['story-graph'])
await service.setBuiltinMcpServerAssignments('story-graph', ['deepseek-harness'])
await expect(service.getEnabledBuiltinMcpServerIds('model')).resolves.not.toContain('story-graph')
const reloaded = new CapabilityService(
filePath,
@@ -388,6 +394,7 @@ describe('CapabilityService', () => {
)
await expect(reloaded.getSnapshot()).resolves.toMatchObject({
builtinMcpServers: expect.arrayContaining([
expect.objectContaining({ id: 'story-graph', assignments: ['deepseek-harness'] }),
expect.objectContaining({
id: 'knowledge-base',
assignments: ['model']