Archived
feat(sessions): wire extension dialogs into the daemon with answer/cancel routes
ctx.ui.confirm()/select()/input() from extensions now open daemon-owned pending dialog records, publish dialog.opened/dialog.closed, and park a Promise that settles on the browser's answer or cancel, the extension's own signal/timeout, the extensionDialogsTimeoutMs daemon default (5 min, 0 = forever; tuning knob, not a gate), agent_end for run-scoped dialogs, or session-ended on close/replace/dispose. Answers resolve the parked extension Promise directly via POST /sessions/:id/dialogs/answer|cancel - never the prompt queue - with first-wins stale semantics across browsers, and SessionStatus.pendingDialogs rehydrates reloading clients.
This commit is contained in:
+29
-1
@@ -2,7 +2,7 @@ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { DEFAULT_MAX_UPLOAD_BYTES, DEFAULT_UPLOADS_FOLDER, agentDirEnvSource, agentSessionDirEnvKeys, askUserEnabled, effectiveAgentConfig, effectivePiWebConfig, hasAgentDirEnvOverride, hasAgentSessionDirEnvOverride, loadPiWebConfig, maxUploadBytes, offlineModeEnabled, savePiWebConfig, spawnSessionsEnabled, subsessionsEnabled } from "./config.js";
|
||||
import { DEFAULT_EXTENSION_DIALOGS_TIMEOUT_MS, DEFAULT_MAX_UPLOAD_BYTES, DEFAULT_UPLOADS_FOLDER, agentDirEnvSource, agentSessionDirEnvKeys, askUserEnabled, effectiveAgentConfig, effectivePiWebConfig, hasAgentDirEnvOverride, hasAgentSessionDirEnvOverride, loadPiWebConfig, maxUploadBytes, offlineModeEnabled, savePiWebConfig, spawnSessionsEnabled, subsessionsEnabled } from "./config.js";
|
||||
|
||||
let tempDir: string;
|
||||
let configPath: string;
|
||||
@@ -63,6 +63,22 @@ describe("PI WEB config persistence", () => {
|
||||
expect(loadPiWebConfig(testOptions()).config.maxUploadBytes).toBe(1234);
|
||||
});
|
||||
|
||||
it("keeps a hand-edited extensionDialogsTimeoutMs across settings saves", async () => {
|
||||
await writeFile(configPath, `${JSON.stringify({ extensionDialogsTimeoutMs: 60_000 }, null, 2)}\n`, "utf8");
|
||||
|
||||
savePiWebConfig({ port: 9000 }, testOptions());
|
||||
|
||||
expect(loadPiWebConfig(testOptions()).config.extensionDialogsTimeoutMs).toBe(60_000);
|
||||
});
|
||||
|
||||
it("rejects an invalid extensionDialogsTimeoutMs", async () => {
|
||||
for (const value of [-1, 1.5, "5000", null]) {
|
||||
await writeFile(configPath, `${JSON.stringify({ extensionDialogsTimeoutMs: value }, null, 2)}\n`, "utf8");
|
||||
|
||||
expect(() => loadPiWebConfig(testOptions())).toThrow("PI WEB config extensionDialogsTimeoutMs must be a non-negative integer");
|
||||
}
|
||||
});
|
||||
|
||||
it("persists and reads custom agent runtime settings", () => {
|
||||
savePiWebConfig({ agent: { command: "acme-agent", dir: "/opt/acme-agent/state" } }, testOptions());
|
||||
|
||||
@@ -223,6 +239,18 @@ describe("maxUploadBytes", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("extensionDialogsTimeoutMs", () => {
|
||||
it("defaults to five minutes when nothing is configured", () => {
|
||||
expect(effectivePiWebConfig(testOptions()).config.extensionDialogsTimeoutMs).toBe(DEFAULT_EXTENSION_DIALOGS_TIMEOUT_MS);
|
||||
});
|
||||
|
||||
it("resolves a configured value, including zero for waiting forever", async () => {
|
||||
await writeFile(configPath, `${JSON.stringify({ extensionDialogsTimeoutMs: 0 }, null, 2)}\n`, "utf8");
|
||||
|
||||
expect(effectivePiWebConfig(testOptions()).config.extensionDialogsTimeoutMs).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("spawnSessionsEnabled", () => {
|
||||
it("is on by default when nothing is configured", () => {
|
||||
expect(spawnSessionsEnabled({}, {})).toBe(true);
|
||||
|
||||
Reference in New Issue
Block a user