Archived
feat: add session runtime reload command
This commit is contained in:
@@ -240,7 +240,7 @@ export class SessionList extends LitElement implements KeyboardNavigableSection
|
||||
<button title="Archive session" @click=${() => { this.openMenuSessionId = undefined; this.onArchive?.(session); }}>Archive</button>
|
||||
${descendantCount > 0 ? html`<button title="Archive this session and its descendants" @click=${() => { this.openMenuSessionId = undefined; this.confirmArchiveWithDescendants(session, descendantCount); }}>Archive with descendants (${descendantCount})</button>` : null}
|
||||
${session.parentSessionPath !== undefined ? html`<button title="Detach from parent" @click=${() => { this.openMenuSessionId = undefined; this.onDetachParent?.(session); }}>Detach from parent</button>` : null}
|
||||
${this.canReload ? html`<button title=${isSessionActive(this.statuses[session.id], this.activities[session.id]) ? "Stop current session activity before reloading" : "Reload session from disk"} ?disabled=${isSessionActive(this.statuses[session.id], this.activities[session.id])} @click=${() => { this.openMenuSessionId = undefined; this.onReload?.(session); }}>Reload</button>` : null}
|
||||
${this.canReload ? html`<button title=${isSessionActive(this.statuses[session.id], this.activities[session.id]) ? "Stop current session activity before reloading from disk" : "Reload session from disk without refreshing Pi runtime resources"} ?disabled=${isSessionActive(this.statuses[session.id], this.activities[session.id])} @click=${() => { this.openMenuSessionId = undefined; this.onReload?.(session); }}>Reload from disk</button>` : null}
|
||||
`}
|
||||
</div>
|
||||
` : null}
|
||||
|
||||
@@ -23,7 +23,7 @@ export class SettingsPackagesPanel extends LitElement {
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<h2>Pi packages</h2>
|
||||
<p>Install, remove, and update packages managed by Pi. Pi packages can provide extensions, skills, prompt templates, themes, and PI WEB browser plugins.</p>
|
||||
<p>Install, remove, and update packages managed by Pi. Pi packages can provide extensions, skills, prompt templates, themes, context/system prompt files, and PI WEB browser plugins.</p>
|
||||
</div>
|
||||
<button class="secondary" ?disabled=${this.loading || this.isOperating} @click=${() => { void this.onReload?.(); }}>Reload</button>
|
||||
</div>
|
||||
|
||||
@@ -37,8 +37,9 @@ describe("Pi package settings helpers", () => {
|
||||
it("describes the browser and session reload follow-up without requiring sessiond restarts", () => {
|
||||
const message = piPackageMutationFollowUpMessage("install");
|
||||
|
||||
expect(message).toContain("Reload the browser page");
|
||||
expect(message).toContain("Reload existing Pi sessions");
|
||||
expect(message).toContain("Type /reload in each idle PI WEB session");
|
||||
expect(message).toContain("extensions, skills, prompt templates, themes, and context/system prompt files");
|
||||
expect(message).toContain("Reload the browser page separately for PI WEB browser plugin changes");
|
||||
expect(message).not.toContain("session daemon");
|
||||
expect(message).not.toContain("sessiond");
|
||||
});
|
||||
|
||||
@@ -54,5 +54,5 @@ export function isPiPackageOperationPending(operation: PiPackageOperationState |
|
||||
|
||||
export function piPackageMutationFollowUpMessage(action: PiPackageMutationAction): string {
|
||||
const verb = action === "install" ? "installed" : action === "remove" ? "removed" : "updated";
|
||||
return `Pi package ${verb}. Reload the browser page to import newly discovered PI WEB browser plugins. Reload existing Pi sessions, or use /reload in Pi, so extensions, skills, prompt templates, and themes are rediscovered.`;
|
||||
return `Pi package ${verb}. Type /reload in each idle PI WEB session to rediscover Pi runtime resources: extensions, skills, prompt templates, themes, and context/system prompt files. Reload the browser page separately for PI WEB browser plugin changes.`;
|
||||
}
|
||||
|
||||
@@ -879,7 +879,7 @@ describe("SessionController", () => {
|
||||
expect(state.error).toContain("requires an updated Pi-Web runtime");
|
||||
});
|
||||
|
||||
it("reloads the selected session, discards the cached transcript, and re-fetches history", async () => {
|
||||
it("reloads the selected session from disk, discards the cached transcript, and re-fetches history", async () => {
|
||||
Object.defineProperty(globalThis, "localStorage", { value: new MemoryStorage(), configurable: true });
|
||||
const reloadCalls: string[] = [];
|
||||
const messageCalls: string[] = [];
|
||||
@@ -917,7 +917,7 @@ describe("SessionController", () => {
|
||||
expect(state.error).toBe("");
|
||||
});
|
||||
|
||||
it("does not reload sessions when the selected machine runtime does not support it", async () => {
|
||||
it("does not reload sessions from disk when the selected machine runtime does not support it", async () => {
|
||||
const reloadCalls: string[] = [];
|
||||
let state: AppState = {
|
||||
...initialAppState(),
|
||||
@@ -943,7 +943,7 @@ describe("SessionController", () => {
|
||||
await controller.reloadSession(oldSession);
|
||||
|
||||
expect(reloadCalls).toEqual([]);
|
||||
expect(state.error).toContain("requires an updated Pi-Web runtime");
|
||||
expect(state.error).toContain("Reloading sessions from disk requires an updated Pi-Web runtime");
|
||||
});
|
||||
|
||||
it("forgets archived selections when the archived section collapse clears selection", async () => {
|
||||
|
||||
@@ -484,7 +484,7 @@ export class SessionController {
|
||||
const machineId = selectedMachineId(this.getState());
|
||||
const runtime = this.getState().machineRuntimes[machineId];
|
||||
if (runtime?.ok !== true || !supportsPiWebCapability(runtime, PI_WEB_CAPABILITIES.sessionsReload)) {
|
||||
this.setState({ error: "Reloading sessions requires an updated Pi-Web runtime on this machine." });
|
||||
this.setState({ error: "Reloading sessions from disk requires an updated Pi-Web runtime on this machine." });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -177,8 +177,8 @@ export function createCoreActions(): PluginAction[] {
|
||||
},
|
||||
{
|
||||
id: "session.reload",
|
||||
title: "Reload Session",
|
||||
description: "Re-read the selected session from disk to pick up entries written by another process",
|
||||
title: "Reload Session from Disk",
|
||||
description: "Close and re-open the selected session from its session file. Use /reload in the prompt for Pi runtime resources.",
|
||||
group: "Session",
|
||||
enabled: hasReloadableSession,
|
||||
disabledReason: reloadSessionDisabledReason,
|
||||
@@ -236,7 +236,7 @@ function reloadSessionDisabledReason(context: { state: AppState }): string | und
|
||||
const session = context.state.selectedSession;
|
||||
if (session === undefined || session.archived === true || isCachedNewSessionInfo(session)) return undefined;
|
||||
if (isSessionActive(context.state.status, context.state.activity)) return undefined;
|
||||
return missingCapabilityReason(context.state, PI_WEB_CAPABILITIES.sessionsReload, "reload sessions");
|
||||
return missingCapabilityReason(context.state, PI_WEB_CAPABILITIES.sessionsReload, "reload sessions from disk");
|
||||
}
|
||||
|
||||
function missingCapabilityReason(state: AppState, capability: PiWebCapability, action: string): string | undefined {
|
||||
|
||||
@@ -187,18 +187,21 @@ describe("PluginRegistry", () => {
|
||||
expect(archivedActions.find((action) => action.id === "core:session.delete")?.enabled).toBe(false);
|
||||
});
|
||||
|
||||
it("enables session reload only for a writable session on a capable, idle runtime", () => {
|
||||
it("enables session disk reload only for a writable session on a capable, idle runtime", () => {
|
||||
const registry = new PluginRegistry();
|
||||
registry.register({ id: "core", plugin: corePlugin });
|
||||
const reloadRuntime = { local: { machineId: "local", ok: true as const, checkedAt: "now", capabilities: [PI_WEB_CAPABILITIES.sessionsReload] } };
|
||||
|
||||
const reloadable = registry.getActions(createContext({ selectedSession: testSession(), machineRuntimes: reloadRuntime }).context);
|
||||
expect(reloadable.find((action) => action.id === "core:session.reload")?.enabled).toBe(true);
|
||||
const reloadableAction = reloadable.find((action) => action.id === "core:session.reload");
|
||||
expect(reloadableAction?.enabled).toBe(true);
|
||||
expect(reloadableAction?.title).toBe("Reload Session from Disk");
|
||||
expect(reloadableAction?.description).toContain("Use /reload in the prompt for Pi runtime resources");
|
||||
|
||||
const noCapability = registry.getActions(createContext({ selectedSession: testSession() }).context);
|
||||
const noCapabilityReload = noCapability.find((action) => action.id === "core:session.reload");
|
||||
expect(noCapabilityReload?.enabled).toBe(false);
|
||||
expect(noCapabilityReload?.disabledReason).toBe("Update and restart Pi-Web on this machine to reload sessions.");
|
||||
expect(noCapabilityReload?.disabledReason).toBe("Update and restart Pi-Web on this machine to reload sessions from disk.");
|
||||
|
||||
const archived = registry.getActions(createContext({ selectedSession: { ...testSession(), archived: true, archivedAt: "2026-05-20T00:00:00.000Z" }, machineRuntimes: reloadRuntime }).context);
|
||||
expect(archived.find((action) => action.id === "core:session.reload")?.enabled).toBe(false);
|
||||
|
||||
Reference in New Issue
Block a user