fix(tui): preserve agent hub persisted gating
This commit is contained in:
@@ -270,9 +270,9 @@ export class AgentHubOverlayComponent extends Container {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the table view has no agents to show (every registered agent except
|
||||
* Main, after the persisted-subagent scan in the constructor). The double-←
|
||||
* gesture reads this to stay inert when there is nothing to open.
|
||||
* Whether the current table view has no agents to show (every registered agent
|
||||
* except Main). Persisted historical rows may arrive later; callers that need
|
||||
* those included must wait for {@link persistedSubagentsReady} first.
|
||||
*/
|
||||
get isEmpty(): boolean {
|
||||
return this.#rows.length === 0;
|
||||
|
||||
@@ -1426,18 +1426,27 @@ export class SelectorController {
|
||||
sessionFile: this.ctx.sessionManager.getSessionFile() ?? null,
|
||||
});
|
||||
|
||||
// The double-← gesture passes requireContent so it stays inert when there
|
||||
// are no subagents to show; the explicit hub/observe keys still open the
|
||||
// empty roster. The freshly built hub already ran the persisted-subagent
|
||||
// scan, so its row count is the authoritative "is there anything to show".
|
||||
const showReadyHub = () => {
|
||||
// The double-← gesture passes requireContent so it stays inert when
|
||||
// neither live nor persisted subagents are available. Persisted rows now
|
||||
// load asynchronously, so defer the gate until that scan has refreshed the
|
||||
// hub instead of treating the initial empty table as authoritative.
|
||||
if (options?.requireContent && hub.isEmpty) {
|
||||
hub.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
this.ctx.editorContainer.clear();
|
||||
this.ctx.editorContainer.addChild(hub);
|
||||
this.ctx.ui.setFocus(hub);
|
||||
this.ctx.ui.requestRender();
|
||||
};
|
||||
|
||||
if (options?.requireContent && hub.isEmpty) {
|
||||
hub.dispose();
|
||||
void hub.persistedSubagentsReady.then(showReadyHub);
|
||||
return;
|
||||
}
|
||||
|
||||
this.ctx.editorContainer.clear();
|
||||
this.ctx.editorContainer.addChild(hub);
|
||||
this.ctx.ui.setFocus(hub);
|
||||
this.ctx.ui.requestRender();
|
||||
showReadyHub();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,8 +188,9 @@ describe("Agent hub double-← gating", () => {
|
||||
resetSettingsForTest();
|
||||
});
|
||||
|
||||
function setup(agents: AgentRegistry) {
|
||||
function setup(agents: AgentRegistry, sessionFile: string | null = null) {
|
||||
let shown: AgentHubOverlayComponent | undefined;
|
||||
const shownReady = Promise.withResolvers<AgentHubOverlayComponent>();
|
||||
const editor = {};
|
||||
const ctx = {
|
||||
keybindings: { getKeys: () => [] },
|
||||
@@ -201,17 +202,20 @@ describe("Agent hub double-← gating", () => {
|
||||
editorContainer: {
|
||||
clear: () => {},
|
||||
addChild: (child: unknown) => {
|
||||
if (child !== editor) shown = child as AgentHubOverlayComponent;
|
||||
if (child !== editor) {
|
||||
shown = child as AgentHubOverlayComponent;
|
||||
shownReady.resolve(shown);
|
||||
}
|
||||
},
|
||||
},
|
||||
collabGuest: { agentRegistry: agents, hubRemote: undefined },
|
||||
focusAgentSession: async () => {},
|
||||
session: { getToolByName: () => undefined, extensionRunner: undefined },
|
||||
sessionManager: { getCwd: () => TEST_CWD, getSessionFile: () => null },
|
||||
sessionManager: { getCwd: () => TEST_CWD, getSessionFile: () => sessionFile },
|
||||
hideThinkingBlock: false,
|
||||
};
|
||||
const controller = new SelectorController(ctx as unknown as InteractiveModeContext);
|
||||
return { controller, shown: () => shown };
|
||||
return { controller, shown: () => shown, shownReady: shownReady.promise };
|
||||
}
|
||||
|
||||
function registerWorker(agents: AgentRegistry) {
|
||||
@@ -254,6 +258,24 @@ describe("Agent hub double-← gating", () => {
|
||||
shown()!.dispose();
|
||||
});
|
||||
|
||||
it("requireContent opens the hub after persisted subagents load", async () => {
|
||||
using tempDir = TempDir.createSync("@omp-agent-hub-require-content-");
|
||||
const sessionFile = path.join(tempDir.path(), "main.jsonl");
|
||||
const workerSessionFile = path.join(tempDir.path(), "main", "Worker.jsonl");
|
||||
await Bun.write(sessionFile, "");
|
||||
await Bun.write(workerSessionFile, "");
|
||||
const agents = new AgentRegistry();
|
||||
const { controller, shown, shownReady } = setup(agents, sessionFile);
|
||||
|
||||
controller.showAgentHub(new SessionObserverRegistry(), { requireContent: true });
|
||||
|
||||
expect(shown()).toBeUndefined();
|
||||
const shownHub = await shownReady;
|
||||
expect(shownHub).toBeDefined();
|
||||
expect(agents.get("Worker")?.sessionFile).toBe(workerSessionFile);
|
||||
shownHub!.dispose();
|
||||
});
|
||||
|
||||
it("the explicit hub key opens the empty roster even with no subagents", () => {
|
||||
const agents = new AgentRegistry();
|
||||
const { controller, shown } = setup(agents);
|
||||
|
||||
Reference in New Issue
Block a user