pi-sessions 0.7.2 → 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 +71 -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} +67 -46
- package/extensions/session-auto-title/model.ts +25 -17
- package/extensions/session-auto-title/retitle.ts +26 -12
- package/extensions/session-auto-title/wizard.ts +12 -6
- 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 +80 -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,9 +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
|
-
|
|
61
|
+
generation: AutoTitleGeneration,
|
|
60
62
|
options?: RetitleWizardOptions,
|
|
61
63
|
): Promise<RetitleCommandOutcome> {
|
|
62
64
|
return ctx.ui.custom<RetitleCommandOutcome>(
|
|
@@ -67,9 +69,10 @@ export async function showRetitleWizard(
|
|
|
67
69
|
pi,
|
|
68
70
|
controller,
|
|
69
71
|
ctx,
|
|
72
|
+
modelRuntime,
|
|
70
73
|
model,
|
|
71
74
|
getSessionEpoch,
|
|
72
|
-
|
|
75
|
+
generation,
|
|
73
76
|
done,
|
|
74
77
|
options,
|
|
75
78
|
),
|
|
@@ -96,9 +99,10 @@ class RetitleWizardPanel implements Focusable {
|
|
|
96
99
|
private readonly pi: ExtensionAPI,
|
|
97
100
|
private readonly controller: SessionAutoTitleController,
|
|
98
101
|
private readonly ctx: ExtensionCommandContext,
|
|
102
|
+
private readonly modelRuntime: ModelRuntime,
|
|
99
103
|
private readonly model: Model<Api> | undefined,
|
|
100
104
|
private readonly getSessionEpoch: () => number,
|
|
101
|
-
private readonly
|
|
105
|
+
private readonly generation: AutoTitleGeneration,
|
|
102
106
|
private readonly done: (result: RetitleCommandOutcome) => void,
|
|
103
107
|
options?: RetitleWizardOptions,
|
|
104
108
|
) {
|
|
@@ -247,9 +251,10 @@ class RetitleWizardPanel implements Focusable {
|
|
|
247
251
|
pi: this.pi,
|
|
248
252
|
controller: this.controller,
|
|
249
253
|
ctx: this.ctx,
|
|
254
|
+
modelRuntime: this.modelRuntime,
|
|
250
255
|
model: this.model,
|
|
251
256
|
isManual: true,
|
|
252
|
-
|
|
257
|
+
generation: this.generation,
|
|
253
258
|
getSessionEpoch: this.getSessionEpoch,
|
|
254
259
|
});
|
|
255
260
|
if (result.ok) {
|
|
@@ -305,11 +310,12 @@ class RetitleWizardPanel implements Focusable {
|
|
|
305
310
|
this.pi,
|
|
306
311
|
this.controller,
|
|
307
312
|
this.ctx,
|
|
313
|
+
this.modelRuntime,
|
|
308
314
|
this.model,
|
|
309
315
|
scan,
|
|
310
316
|
mode,
|
|
311
317
|
this.getSessionEpoch,
|
|
312
|
-
this.
|
|
318
|
+
this.generation,
|
|
313
319
|
);
|
|
314
320
|
notifyBulkRetitleResult(this.ctx, scan, mode, result);
|
|
315
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
|
+
}
|