feat(story-115): hot-reload project.toml agent config without server restart

- Extend `WatcherEvent` to an enum with `WorkItem` and `ConfigChanged` variants
  so the watcher can distinguish between pipeline-file changes and config changes
- Watch `.story_kit/project.toml` at the project root (ignoring worktree copies)
  and broadcast `WatcherEvent::ConfigChanged` on modification
- Forward `agent_config_changed` WebSocket message to connected clients; skip
  pipeline state refresh for config-only events
- Add `is_config_file()` helper with unit tests covering root vs. worktree paths
- Accept `configVersion` prop in `AgentPanel` and re-fetch the agent roster
  whenever it increments
- Increment `agentConfigVersion` in `Chat` on receipt of `agent_config_changed`
  WS event via new `onAgentConfigChanged` handler in `ChatWebSocket`

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dave
2026-02-23 22:58:51 +00:00
parent 662df66c13
commit e6339979de
6 changed files with 176 additions and 33 deletions

View File

@@ -57,7 +57,9 @@ export type WsResponse =
story_id: string;
status: string;
message: string;
};
}
/** `.story_kit/project.toml` was modified; re-fetch the agent roster. */
| { type: "agent_config_changed" };
export interface ProviderConfig {
provider: string;
@@ -273,6 +275,7 @@ export class ChatWebSocket {
status: string,
message: string,
) => void;
private onAgentConfigChanged?: () => void;
private connected = false;
private closeTimer?: number;
private wsPath = DEFAULT_WS_PATH;
@@ -322,6 +325,7 @@ export class ChatWebSocket {
data.status,
data.message,
);
if (data.type === "agent_config_changed") this.onAgentConfigChanged?.();
} catch (err) {
this.onError?.(String(err));
}
@@ -367,6 +371,7 @@ export class ChatWebSocket {
status: string,
message: string,
) => void;
onAgentConfigChanged?: () => void;
},
wsPath = DEFAULT_WS_PATH,
) {
@@ -378,6 +383,7 @@ export class ChatWebSocket {
this.onPermissionRequest = handlers.onPermissionRequest;
this.onActivity = handlers.onActivity;
this.onReconciliationProgress = handlers.onReconciliationProgress;
this.onAgentConfigChanged = handlers.onAgentConfigChanged;
this.wsPath = wsPath;
this.shouldReconnect = true;