pi-sessions 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -37
- package/extensions/pi-sessions.ts +125 -0
- package/extensions/session-ask/agent.ts +34 -14
- package/extensions/{session-ask.ts → session-ask/install.ts} +73 -90
- package/extensions/session-ask/navigate.ts +3 -1
- package/extensions/session-ask/presenter.ts +23 -0
- package/extensions/session-ask/renderer.ts +63 -0
- package/extensions/session-ask/tool-contract.ts +27 -0
- package/extensions/session-ask/view-model.ts +18 -0
- package/extensions/session-auto-title/generate.ts +18 -18
- package/extensions/{session-auto-title.ts → session-auto-title/install.ts} +60 -53
- package/extensions/session-auto-title/model.ts +25 -17
- package/extensions/session-auto-title/retitle.ts +17 -18
- package/extensions/session-auto-title/wizard.ts +12 -11
- package/extensions/session-handoff/board-view-model.ts +181 -0
- package/extensions/session-handoff/board.ts +663 -0
- package/extensions/session-handoff/bootstrap.ts +174 -0
- package/extensions/session-handoff/extract.ts +101 -122
- package/extensions/session-handoff/install.ts +225 -0
- package/extensions/session-handoff/kickoff.ts +92 -0
- package/extensions/session-handoff/launch/backend.ts +16 -0
- package/extensions/session-handoff/launch/deferred.ts +20 -0
- package/extensions/session-handoff/launch/ghostty.ts +99 -0
- package/extensions/session-handoff/launch/resolution.ts +57 -0
- package/extensions/session-handoff/launch/shell.ts +7 -0
- package/extensions/session-handoff/launch/tmux.ts +31 -0
- package/extensions/session-handoff/launch-options.ts +61 -0
- package/extensions/session-handoff/launch-target.ts +91 -0
- package/extensions/session-handoff/metadata.ts +152 -63
- package/extensions/session-handoff/model.ts +58 -0
- package/extensions/session-handoff/query.ts +0 -1
- package/extensions/session-handoff/receipt.ts +96 -0
- package/extensions/session-handoff/review.ts +2 -28
- package/extensions/session-handoff/spawn.ts +76 -181
- package/extensions/session-handoff/strong-modal.ts +13 -0
- package/extensions/session-handoff/tool-contract.ts +12 -0
- package/extensions/session-handoff/tool-presenter.ts +35 -0
- package/extensions/session-handoff/tool-renderer.ts +66 -0
- package/extensions/session-handoff/tool-schema.ts +54 -0
- package/extensions/session-handoff/tool-view-model.ts +49 -0
- package/extensions/session-handoff/tool.ts +206 -0
- package/extensions/session-handoff/ui.ts +66 -0
- package/extensions/session-hooks/install.ts +75 -0
- package/extensions/{session-index.ts → session-index/install.ts} +9 -7
- package/extensions/session-messaging/broker/process.ts +21 -28
- package/extensions/session-messaging/install.ts +78 -0
- package/extensions/session-messaging/pi/cancel-session-presenter.ts +64 -0
- package/extensions/session-messaging/pi/incoming-message-presenter.ts +32 -0
- package/extensions/session-messaging/pi/incoming-message-view-model.ts +20 -0
- package/extensions/session-messaging/pi/incoming-runtime.ts +27 -23
- package/extensions/session-messaging/pi/message-contracts.ts +32 -0
- package/extensions/session-messaging/pi/renderer.ts +19 -12
- package/extensions/session-messaging/pi/send-message-presenter.ts +39 -0
- package/extensions/session-messaging/pi/send-message-view-model.ts +54 -0
- package/extensions/session-messaging/pi/service.ts +262 -81
- package/extensions/session-messaging/pi/tools.ts +184 -40
- package/extensions/session-search/extract.ts +60 -14
- package/extensions/session-search/hooks.ts +10 -13
- package/extensions/session-search/install.ts +373 -0
- package/extensions/session-search/renderer.ts +195 -0
- package/extensions/session-search/tool-contract.ts +51 -0
- package/extensions/shared/composition.ts +20 -0
- package/extensions/shared/errors.ts +3 -0
- package/extensions/shared/model-resolution.ts +73 -0
- package/extensions/shared/model-runtime.ts +33 -0
- package/extensions/shared/model.ts +7 -10
- package/extensions/shared/rendering/collapsible-text.ts +89 -0
- package/extensions/shared/rendering/expandable-content-layout.ts +84 -0
- package/extensions/shared/rendering/theme.ts +5 -0
- package/extensions/shared/session-broker/client.ts +30 -29
- package/extensions/shared/session-broker/protocol.ts +128 -10
- package/extensions/shared/session-index/common.ts +5 -5
- package/extensions/shared/session-index/lineage.ts +0 -3
- package/extensions/shared/session-index/schema.ts +0 -1
- package/extensions/shared/session-index/scoring.ts +1 -2
- package/extensions/shared/session-index/search.ts +11 -4
- package/extensions/shared/session-index/store.ts +4 -9
- package/extensions/shared/settings.ts +76 -38
- package/extensions/shared/text.ts +5 -0
- package/extensions/shared/thinking-levels.ts +22 -0
- package/extensions/shared/tmux.ts +205 -0
- package/extensions/subagents/cancel.ts +111 -0
- package/extensions/subagents/classify.ts +52 -0
- package/extensions/subagents/install.ts +344 -0
- package/extensions/subagents/launch-target.ts +75 -0
- package/extensions/subagents/ledger.ts +217 -0
- package/extensions/subagents/reconcile.ts +386 -0
- package/extensions/subagents/report-message-presenter.ts +36 -0
- package/extensions/subagents/report-message-renderer.ts +21 -0
- package/extensions/subagents/report-message-view-model.ts +29 -0
- package/extensions/subagents/report.ts +159 -0
- package/extensions/subagents/roster.ts +262 -0
- package/extensions/subagents/wake.ts +173 -0
- package/images/handoff-board-subagents.png +0 -0
- package/images/handoff-board-user-sessions.png +0 -0
- package/images/handoff-subagent-report.png +0 -0
- package/images/session-handoff-tool.png +0 -0
- package/package.json +10 -16
- package/extensions/session-handoff.ts +0 -741
- package/extensions/session-hooks.ts +0 -75
- package/extensions/session-messaging/pi/message-view.ts +0 -131
- package/extensions/session-messaging.ts +0 -30
- package/extensions/session-search.ts +0 -419
- package/extensions/shared/session-broker/active.ts +0 -26
|
@@ -3,13 +3,14 @@ import {
|
|
|
3
3
|
copyToClipboard,
|
|
4
4
|
type ExtensionAPI,
|
|
5
5
|
type ExtensionCommandContext,
|
|
6
|
+
type ModelRuntime,
|
|
6
7
|
type Theme,
|
|
7
8
|
} from "@earendil-works/pi-coding-agent";
|
|
8
9
|
import type { Focusable, TUI } from "@earendil-works/pi-tui";
|
|
9
10
|
import { matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
10
11
|
import type { RetitleCommandOutcome, RetitleMode, RetitleScope } from "./command.ts";
|
|
11
12
|
import type { AutoRetitleStatus, SessionAutoTitleController } from "./controller.ts";
|
|
12
|
-
import type { AutoTitleFailure } from "./generate.ts";
|
|
13
|
+
import type { AutoTitleFailure, AutoTitleGeneration } from "./generate.ts";
|
|
13
14
|
import {
|
|
14
15
|
buildBulkRetitleMessage,
|
|
15
16
|
buildRetitleScopeScan,
|
|
@@ -54,10 +55,10 @@ export async function showRetitleWizard(
|
|
|
54
55
|
pi: ExtensionAPI,
|
|
55
56
|
controller: SessionAutoTitleController,
|
|
56
57
|
ctx: ExtensionCommandContext,
|
|
58
|
+
modelRuntime: ModelRuntime,
|
|
57
59
|
model: Model<Api> | undefined,
|
|
58
60
|
getSessionEpoch: () => number,
|
|
59
|
-
|
|
60
|
-
timeoutMs: number,
|
|
61
|
+
generation: AutoTitleGeneration,
|
|
61
62
|
options?: RetitleWizardOptions,
|
|
62
63
|
): Promise<RetitleCommandOutcome> {
|
|
63
64
|
return ctx.ui.custom<RetitleCommandOutcome>(
|
|
@@ -68,10 +69,10 @@ export async function showRetitleWizard(
|
|
|
68
69
|
pi,
|
|
69
70
|
controller,
|
|
70
71
|
ctx,
|
|
72
|
+
modelRuntime,
|
|
71
73
|
model,
|
|
72
74
|
getSessionEpoch,
|
|
73
|
-
|
|
74
|
-
timeoutMs,
|
|
75
|
+
generation,
|
|
75
76
|
done,
|
|
76
77
|
options,
|
|
77
78
|
),
|
|
@@ -98,10 +99,10 @@ class RetitleWizardPanel implements Focusable {
|
|
|
98
99
|
private readonly pi: ExtensionAPI,
|
|
99
100
|
private readonly controller: SessionAutoTitleController,
|
|
100
101
|
private readonly ctx: ExtensionCommandContext,
|
|
102
|
+
private readonly modelRuntime: ModelRuntime,
|
|
101
103
|
private readonly model: Model<Api> | undefined,
|
|
102
104
|
private readonly getSessionEpoch: () => number,
|
|
103
|
-
private readonly
|
|
104
|
-
private readonly timeoutMs: number,
|
|
105
|
+
private readonly generation: AutoTitleGeneration,
|
|
105
106
|
private readonly done: (result: RetitleCommandOutcome) => void,
|
|
106
107
|
options?: RetitleWizardOptions,
|
|
107
108
|
) {
|
|
@@ -250,10 +251,10 @@ class RetitleWizardPanel implements Focusable {
|
|
|
250
251
|
pi: this.pi,
|
|
251
252
|
controller: this.controller,
|
|
252
253
|
ctx: this.ctx,
|
|
254
|
+
modelRuntime: this.modelRuntime,
|
|
253
255
|
model: this.model,
|
|
254
256
|
isManual: true,
|
|
255
|
-
|
|
256
|
-
timeoutMs: this.timeoutMs,
|
|
257
|
+
generation: this.generation,
|
|
257
258
|
getSessionEpoch: this.getSessionEpoch,
|
|
258
259
|
});
|
|
259
260
|
if (result.ok) {
|
|
@@ -309,12 +310,12 @@ class RetitleWizardPanel implements Focusable {
|
|
|
309
310
|
this.pi,
|
|
310
311
|
this.controller,
|
|
311
312
|
this.ctx,
|
|
313
|
+
this.modelRuntime,
|
|
312
314
|
this.model,
|
|
313
315
|
scan,
|
|
314
316
|
mode,
|
|
315
317
|
this.getSessionEpoch,
|
|
316
|
-
this.
|
|
317
|
-
this.timeoutMs,
|
|
318
|
+
this.generation,
|
|
318
319
|
);
|
|
319
320
|
notifyBulkRetitleResult(this.ctx, scan, mode, result);
|
|
320
321
|
this.done(
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { tmuxSessionName } from "../shared/tmux.ts";
|
|
2
|
+
import type { SubagentState } from "../subagents/classify.ts";
|
|
3
|
+
import type { SubagentRosterEntry } from "../subagents/roster.ts";
|
|
4
|
+
import { shellQuote } from "./launch/shell.ts";
|
|
5
|
+
import type { HandoffLaunchReceipt } from "./receipt.ts";
|
|
6
|
+
|
|
7
|
+
const RUNNING_SUBAGENT_STATES: ReadonlySet<SubagentState> = new Set(["starting", "busy", "active"]);
|
|
8
|
+
|
|
9
|
+
export type HandoffBoardTab = "subagents" | "user-sessions";
|
|
10
|
+
export type UserSessionStatus = "live" | "ready" | "starting" | "closed" | "unknown";
|
|
11
|
+
|
|
12
|
+
export interface UserSessionRunEvidence {
|
|
13
|
+
transcriptAvailable: boolean;
|
|
14
|
+
hasStarted: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface UserSessionEntry {
|
|
18
|
+
sessionId: string;
|
|
19
|
+
timestamp: string;
|
|
20
|
+
receipt: HandoffLaunchReceipt;
|
|
21
|
+
runEvidence?: UserSessionRunEvidence | undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface HandoffBoardSnapshot {
|
|
25
|
+
subagents: readonly SubagentRosterEntry[];
|
|
26
|
+
userSessions: readonly UserSessionEntry[];
|
|
27
|
+
liveSessionIds: ReadonlySet<string>;
|
|
28
|
+
hasLiveSessionEvidence: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface HandoffBoardDetail {
|
|
32
|
+
label: string;
|
|
33
|
+
value: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface HandoffBoardAction {
|
|
37
|
+
subagent?: SubagentRosterEntry | undefined;
|
|
38
|
+
canStop: boolean;
|
|
39
|
+
observeCommand?: string | undefined;
|
|
40
|
+
resumeCommand?: string | undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface HandoffSubagentRow {
|
|
44
|
+
kind: "subagent";
|
|
45
|
+
title: string;
|
|
46
|
+
depth: number;
|
|
47
|
+
status: SubagentState;
|
|
48
|
+
timestamp: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface UserSessionRow {
|
|
52
|
+
kind: "user-session";
|
|
53
|
+
title: string;
|
|
54
|
+
status: UserSessionStatus;
|
|
55
|
+
timestamp: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface HandoffSubagentsView {
|
|
59
|
+
tab: "subagents";
|
|
60
|
+
rows: readonly HandoffSubagentRow[];
|
|
61
|
+
details: readonly HandoffBoardDetail[];
|
|
62
|
+
action?: HandoffBoardAction | undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface UserSessionsView {
|
|
66
|
+
tab: "user-sessions";
|
|
67
|
+
rows: readonly UserSessionRow[];
|
|
68
|
+
details: readonly HandoffBoardDetail[];
|
|
69
|
+
action?: HandoffBoardAction | undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type HandoffBoardView = HandoffSubagentsView | UserSessionsView;
|
|
73
|
+
|
|
74
|
+
export function buildHandoffBoardView(
|
|
75
|
+
snapshot: HandoffBoardSnapshot,
|
|
76
|
+
tab: HandoffBoardTab,
|
|
77
|
+
selectedIndex: number,
|
|
78
|
+
options: { insideTmux: boolean },
|
|
79
|
+
): HandoffBoardView {
|
|
80
|
+
if (tab === "subagents") {
|
|
81
|
+
const selected = snapshot.subagents[selectedIndex];
|
|
82
|
+
return {
|
|
83
|
+
tab,
|
|
84
|
+
rows: snapshot.subagents.map((subagent) => ({
|
|
85
|
+
kind: "subagent",
|
|
86
|
+
title: subagent.title,
|
|
87
|
+
depth: subagent.depth,
|
|
88
|
+
status: subagent.state,
|
|
89
|
+
timestamp: subagent.launchedAt,
|
|
90
|
+
})),
|
|
91
|
+
details: selected
|
|
92
|
+
? [
|
|
93
|
+
{ label: "Session", value: selected.sessionId },
|
|
94
|
+
{ label: "Model", value: selected.model ?? "Default" },
|
|
95
|
+
{
|
|
96
|
+
label: "Owner",
|
|
97
|
+
value: selected.ownerIsCurrentSession ? "this session" : selected.ownerTitle,
|
|
98
|
+
},
|
|
99
|
+
{ label: "Goal", value: selected.goal },
|
|
100
|
+
]
|
|
101
|
+
: [],
|
|
102
|
+
...(selected ? { action: buildSubagentAction(selected, options.insideTmux) } : {}),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const rows = snapshot.userSessions.map(
|
|
107
|
+
(entry): UserSessionRow => ({
|
|
108
|
+
kind: "user-session",
|
|
109
|
+
title: entry.receipt.title,
|
|
110
|
+
status: getUserSessionStatus(snapshot, entry),
|
|
111
|
+
timestamp: entry.timestamp,
|
|
112
|
+
}),
|
|
113
|
+
);
|
|
114
|
+
const selected = snapshot.userSessions[selectedIndex];
|
|
115
|
+
if (!selected) {
|
|
116
|
+
return { tab, rows, details: [] };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const details: HandoffBoardDetail[] = [
|
|
120
|
+
{ label: "Session", value: selected.sessionId },
|
|
121
|
+
{ label: "Model", value: selected.receipt.model },
|
|
122
|
+
{ label: "Launch", value: selected.receipt.launch },
|
|
123
|
+
];
|
|
124
|
+
if (selected.receipt.backend) {
|
|
125
|
+
details.push({ label: "Backend", value: selected.receipt.backend });
|
|
126
|
+
}
|
|
127
|
+
if (selected.receipt.cwd) {
|
|
128
|
+
details.push({ label: "Directory", value: selected.receipt.cwd });
|
|
129
|
+
}
|
|
130
|
+
const action = buildUserSessionAction(snapshot, selected);
|
|
131
|
+
return {
|
|
132
|
+
tab,
|
|
133
|
+
rows,
|
|
134
|
+
details,
|
|
135
|
+
...(action ? { action } : {}),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function getUserSessionStatus(
|
|
140
|
+
snapshot: HandoffBoardSnapshot,
|
|
141
|
+
entry: UserSessionEntry,
|
|
142
|
+
): UserSessionStatus {
|
|
143
|
+
if (snapshot.liveSessionIds.has(entry.sessionId)) {
|
|
144
|
+
return "live";
|
|
145
|
+
}
|
|
146
|
+
const evidence = entry.runEvidence;
|
|
147
|
+
if (!evidence?.transcriptAvailable) {
|
|
148
|
+
return "unknown";
|
|
149
|
+
}
|
|
150
|
+
if (evidence.hasStarted) {
|
|
151
|
+
return snapshot.hasLiveSessionEvidence ? "closed" : "unknown";
|
|
152
|
+
}
|
|
153
|
+
return entry.receipt.launch === "deferred" ? "ready" : "starting";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function buildUserSessionAction(
|
|
157
|
+
snapshot: HandoffBoardSnapshot,
|
|
158
|
+
entry: UserSessionEntry,
|
|
159
|
+
): HandoffBoardAction | undefined {
|
|
160
|
+
if (!snapshot.hasLiveSessionEvidence || snapshot.liveSessionIds.has(entry.sessionId)) {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
canStop: false,
|
|
165
|
+
resumeCommand: entry.receipt.resumeCommand,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function buildSubagentAction(entry: SubagentRosterEntry, insideTmux: boolean): HandoffBoardAction {
|
|
170
|
+
return {
|
|
171
|
+
subagent: entry,
|
|
172
|
+
canStop: RUNNING_SUBAGENT_STATES.has(entry.state),
|
|
173
|
+
...(entry.tmuxWindowId ? { observeCommand: buildObserveCommand(entry, insideTmux) } : {}),
|
|
174
|
+
...(!entry.managedLive ? { resumeCommand: entry.resumeCommand } : {}),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function buildObserveCommand(entry: SubagentRosterEntry, insideTmux: boolean): string {
|
|
179
|
+
const target = shellQuote(`${tmuxSessionName(entry.ownerSessionId)}:${entry.tmuxWindowId}`);
|
|
180
|
+
return insideTmux ? `tmux switch-client -t ${target}` : `tmux attach-session -t ${target}`;
|
|
181
|
+
}
|