@tryinget/pi-activity-strip 0.2.0 → 0.4.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 +37 -6
- package/bin/pi-activity-strip.mjs +55 -5
- package/examples/simulate-sessions.mjs +6 -1
- package/extensions/activity-strip.js +8 -2
- package/extensions/activity-strip.ts +6 -0
- package/package.json +9 -8
- package/src/broker/server.mjs +24 -3
- package/src/broker/session-store.mjs +24 -4
- package/src/client/broker-client.mjs +23 -3
- package/src/client/launcher.mjs +6 -0
- package/src/client/session-telemetry.mjs +87 -8
- package/src/common/activity-order.mjs +68 -0
- package/src/common/alignment-controller.mjs +74 -0
- package/src/common/card-display.mjs +48 -0
- package/src/common/compatibility.mjs +14 -2
- package/src/common/constants.mjs +12 -0
- package/src/common/contracts.d.ts +22 -1
- package/src/common/contracts.ts +22 -1
- package/src/common/electron.mjs +6 -0
- package/src/common/format.mjs +6 -0
- package/src/common/niri-focus.mjs +322 -0
- package/src/common/protocol.mjs +9 -0
- package/src/common/status-report.mjs +6 -0
- package/src/common/telemetry.mjs +16 -3
- package/src/electron/main.mjs +307 -127
- package/src/electron/niri-native-window-runtime.mjs +178 -0
- package/src/electron/niri-workspace-events.mjs +81 -0
- package/src/electron/preload.cjs +40 -0
- package/src/electron/renderer-visibility-runtime.mjs +107 -0
- package/src/electron/workspace-view-runtime.mjs +360 -0
- package/src/ui/strip-html.mjs +371 -246
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// ---
|
|
2
|
+
// summary: "provides deterministic monitoring-first strip ordering while preserving operator-defined order"
|
|
3
|
+
// read_when:
|
|
4
|
+
// - "changing activity grouping, calm-cadence reconciliation, or manual card order"
|
|
5
|
+
// ---
|
|
6
|
+
|
|
7
|
+
const ACTIVE_STATES = new Set(["thinking", "tool", "waiting"]);
|
|
8
|
+
|
|
9
|
+
/** @param {{ state?: string; agentActive?: boolean }} session */
|
|
10
|
+
export function isActiveSession(session) {
|
|
11
|
+
return Boolean(session?.agentActive || ACTIVE_STATES.has(String(session?.state ?? "")));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** @param {{ state?: string; toolName?: string; toolTarget?: string }} session */
|
|
15
|
+
export function isMonitoringSession(session) {
|
|
16
|
+
return Boolean(
|
|
17
|
+
session?.state === "success" &&
|
|
18
|
+
!String(session?.toolName ?? "").trim() &&
|
|
19
|
+
!String(session?.toolTarget ?? "").trim(),
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Reconcile at the calm clock: green settled/monitoring cards first, then active cards,
|
|
25
|
+
* then other inactive cards. Preserve previous/manual order inside each group and append
|
|
26
|
+
* new cards deterministically.
|
|
27
|
+
* @param {Array<{ sessionId: string; state?: string; agentActive?: boolean; toolName?: string; toolTarget?: string; updatedAt?: number }>} sessions
|
|
28
|
+
* @param {string[]} previousOrder
|
|
29
|
+
* @param {{ regroup?: boolean }} [options]
|
|
30
|
+
*/
|
|
31
|
+
export function reconcileActivityOrder(sessions, previousOrder = [], { regroup = true } = {}) {
|
|
32
|
+
const byId = new Map(sessions.map((session) => [session.sessionId, session]));
|
|
33
|
+
const surviving = previousOrder.filter((id) => byId.has(id));
|
|
34
|
+
const known = new Set(surviving);
|
|
35
|
+
for (const session of sessions) {
|
|
36
|
+
if (!session.sessionId || known.has(session.sessionId)) continue;
|
|
37
|
+
surviving.push(session.sessionId);
|
|
38
|
+
known.add(session.sessionId);
|
|
39
|
+
}
|
|
40
|
+
if (!regroup) return surviving;
|
|
41
|
+
|
|
42
|
+
const priorIndex = new Map(surviving.map((id, index) => [id, index]));
|
|
43
|
+
const ordered = [...sessions].sort((left, right) => {
|
|
44
|
+
const leftPriority = isMonitoringSession(left) ? 2 : isActiveSession(left) ? 1 : 0;
|
|
45
|
+
const rightPriority = isMonitoringSession(right) ? 2 : isActiveSession(right) ? 1 : 0;
|
|
46
|
+
const groupDelta = rightPriority - leftPriority;
|
|
47
|
+
if (groupDelta) return groupDelta;
|
|
48
|
+
const leftPrior = priorIndex.get(left.sessionId);
|
|
49
|
+
const rightPrior = priorIndex.get(right.sessionId);
|
|
50
|
+
if (leftPrior != null || rightPrior != null) {
|
|
51
|
+
return (leftPrior ?? Number.MAX_SAFE_INTEGER) - (rightPrior ?? Number.MAX_SAFE_INTEGER);
|
|
52
|
+
}
|
|
53
|
+
const updateDelta = Number(right.updatedAt ?? 0) - Number(left.updatedAt ?? 0);
|
|
54
|
+
if (updateDelta) return updateDelta;
|
|
55
|
+
return left.sessionId.localeCompare(right.sessionId);
|
|
56
|
+
});
|
|
57
|
+
return ordered.map((session) => session.sessionId).filter((id) => byId.has(id));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** @param {string[]} order @param {string} sessionId @param {-1 | 1} delta */
|
|
61
|
+
export function moveOrderItem(order, sessionId, delta) {
|
|
62
|
+
const next = [...order];
|
|
63
|
+
const from = next.indexOf(sessionId);
|
|
64
|
+
const to = from + delta;
|
|
65
|
+
if (from < 0 || to < 0 || to >= next.length) return next;
|
|
66
|
+
[next[from], next[to]] = [next[to], next[from]];
|
|
67
|
+
return next;
|
|
68
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// ---
|
|
2
|
+
// summary: "coalesces native-window alignment so stale async work cannot overwrite newer geometry"
|
|
3
|
+
// read_when:
|
|
4
|
+
// - "changing Electron/Niri geometry reconciliation or testing rapid expansion transitions"
|
|
5
|
+
// ---
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {{ is_floating?: boolean, layout?: { tile_pos_in_workspace_view?: unknown } } | null | undefined} window
|
|
9
|
+
*/
|
|
10
|
+
export function hasNiriFloatingPosition(window) {
|
|
11
|
+
const position = window?.layout?.tile_pos_in_workspace_view;
|
|
12
|
+
return window?.is_floating === true && Array.isArray(position) && position.length >= 2;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {{ is_floating?: boolean, layout?: { tile_pos_in_workspace_view?: unknown, window_size?: unknown } } | null | undefined} window
|
|
17
|
+
* @param {{x: number, y: number, width: number, height: number}} target
|
|
18
|
+
*/
|
|
19
|
+
export function isNiriWindowAligned(window, target) {
|
|
20
|
+
if (!hasNiriFloatingPosition(window)) return false;
|
|
21
|
+
const position = window?.layout?.tile_pos_in_workspace_view;
|
|
22
|
+
const size = window?.layout?.window_size;
|
|
23
|
+
return Boolean(
|
|
24
|
+
Array.isArray(position) &&
|
|
25
|
+
Array.isArray(size) &&
|
|
26
|
+
Number(size[0]) === target.width &&
|
|
27
|
+
Number(size[1]) === target.height &&
|
|
28
|
+
Math.abs(Number(position[0]) - target.x) < 1 &&
|
|
29
|
+
Math.abs(Number(position[1]) - target.y) < 1,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {(attempt: { generation: number, isCurrent: () => boolean }) => Promise<void>} run
|
|
35
|
+
*/
|
|
36
|
+
export function createLatestOnlyRunner(run) {
|
|
37
|
+
if (typeof run !== "function") throw new TypeError("run must be a function");
|
|
38
|
+
|
|
39
|
+
let requestedGeneration = 0;
|
|
40
|
+
/** @type {Promise<void> | null} */
|
|
41
|
+
let worker = null;
|
|
42
|
+
|
|
43
|
+
async function drain() {
|
|
44
|
+
while (true) {
|
|
45
|
+
const generation = requestedGeneration;
|
|
46
|
+
const isCurrent = () => generation === requestedGeneration;
|
|
47
|
+
try {
|
|
48
|
+
await run({ generation, isCurrent });
|
|
49
|
+
} catch {
|
|
50
|
+
// Alignment is best effort. A newer request must still be allowed to reconcile the window.
|
|
51
|
+
}
|
|
52
|
+
if (isCurrent()) return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function request() {
|
|
57
|
+
requestedGeneration += 1;
|
|
58
|
+
if (!worker) {
|
|
59
|
+
worker = drain().finally(() => {
|
|
60
|
+
worker = null;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return requestedGeneration;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function waitForIdle() {
|
|
67
|
+
await worker;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
request,
|
|
72
|
+
waitForIdle,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// ---
|
|
2
|
+
// summary: "derives card display facts that depend on more than one session field"
|
|
3
|
+
// read_when:
|
|
4
|
+
// - "changing stalled-session detection, duplicate label disambiguation, or card label rendering"
|
|
5
|
+
// ---
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A session is stalled when it claims to be mid-activity but no lifecycle
|
|
9
|
+
* event has arrived for longer than the stall threshold. Wedged streams keep
|
|
10
|
+
* heartbeating liveness, so only real event time can expose them.
|
|
11
|
+
* @param {Record<string, unknown>} session
|
|
12
|
+
* @param {number} nowMs
|
|
13
|
+
* @param {number} stallMs
|
|
14
|
+
*/
|
|
15
|
+
export function isStalledSession(session, nowMs, stallMs) {
|
|
16
|
+
if (!session.agentActive) return false;
|
|
17
|
+
const state = String(session.state ?? "");
|
|
18
|
+
if (state !== "thinking" && state !== "tool" && state !== "waiting") return false;
|
|
19
|
+
const anchor = Number(session.lastEventAt || session.updatedAt || 0);
|
|
20
|
+
return anchor > 0 && nowMs - anchor > stallMs;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {Array<Record<string, unknown>>} sessions
|
|
25
|
+
* @returns {Set<string>}
|
|
26
|
+
*/
|
|
27
|
+
export function findDuplicateLabels(sessions) {
|
|
28
|
+
const counts = new Map();
|
|
29
|
+
for (const session of sessions) {
|
|
30
|
+
const label = String(session.repoLabel || "pi session");
|
|
31
|
+
counts.set(label, (counts.get(label) || 0) + 1);
|
|
32
|
+
}
|
|
33
|
+
return new Set([...counts.entries()].filter(([, count]) => count > 1).map(([label]) => label));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Two live processes can share one repo label; append a short process suffix
|
|
38
|
+
* so their cards stay distinguishable at a glance.
|
|
39
|
+
* @param {Record<string, unknown>} session
|
|
40
|
+
* @param {Set<string>} duplicateLabels
|
|
41
|
+
*/
|
|
42
|
+
export function disambiguatedRepoLabel(session, duplicateLabels) {
|
|
43
|
+
const label = String(session.repoLabel || "pi session");
|
|
44
|
+
const processId = Number(session.processId ?? 0);
|
|
45
|
+
return duplicateLabels.has(label) && processId > 0
|
|
46
|
+
? `${label} · ${String(processId).slice(-4)}`
|
|
47
|
+
: label;
|
|
48
|
+
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// ---
|
|
2
|
+
// summary: "detects desktop and Electron prerequisites and formats actionable activity-strip compatibility reports"
|
|
3
|
+
// read_when:
|
|
4
|
+
// - "changing host detection, compatibility blockers, warnings, or doctor output"
|
|
5
|
+
// ---
|
|
6
|
+
|
|
1
7
|
import { execFile } from "node:child_process";
|
|
2
8
|
import { promisify } from "node:util";
|
|
3
9
|
import { locateElectron } from "./electron.mjs";
|
|
@@ -85,6 +91,12 @@ export async function assessActivityStripCompatibility(options = {}) {
|
|
|
85
91
|
);
|
|
86
92
|
}
|
|
87
93
|
|
|
94
|
+
if (windowManager === "niri" && displayCount === 0) {
|
|
95
|
+
blockers.push(
|
|
96
|
+
"Niri reports no connected display outputs. Turn on or reconnect the monitor before opening the activity strip.",
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
88
100
|
try {
|
|
89
101
|
electronPath = await locateElectronImpl();
|
|
90
102
|
} catch (error) {
|
|
@@ -111,7 +123,7 @@ export async function assessActivityStripCompatibility(options = {}) {
|
|
|
111
123
|
displayCount,
|
|
112
124
|
alignmentMode: windowManager === "niri" ? "niri" : "generic",
|
|
113
125
|
primaryDisplayOnly: true,
|
|
114
|
-
clickThroughDefault: env.PI_ACTIVITY_STRIP_CLICK_THROUGH
|
|
126
|
+
clickThroughDefault: env.PI_ACTIVITY_STRIP_CLICK_THROUGH === "1",
|
|
115
127
|
blockers,
|
|
116
128
|
warnings,
|
|
117
129
|
};
|
|
@@ -128,7 +140,7 @@ export function formatCompatibilityReport(report) {
|
|
|
128
140
|
`Electron: ${report.electronPath || "not found"}`,
|
|
129
141
|
`Alignment mode: ${report.alignmentMode}`,
|
|
130
142
|
`Primary-display only: ${report.primaryDisplayOnly ? "yes" : "no"}`,
|
|
131
|
-
`Click-through
|
|
143
|
+
`Click-through mode: ${report.clickThroughDefault ? "enabled by environment" : "disabled (interactive default)"}`,
|
|
132
144
|
];
|
|
133
145
|
|
|
134
146
|
if (typeof report.displayCount === "number") {
|
package/src/common/constants.mjs
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// ---
|
|
2
|
+
// summary: "defines shared socket paths, window dimensions, timing thresholds, and Electron binary candidates"
|
|
3
|
+
// read_when:
|
|
4
|
+
// - "tuning activity-strip runtime defaults or locating shared configuration values"
|
|
5
|
+
// ---
|
|
6
|
+
|
|
1
7
|
import os from "node:os";
|
|
2
8
|
import path from "node:path";
|
|
3
9
|
|
|
@@ -15,6 +21,10 @@ export const ACTIVITY_STRIP_SOCKET_PATH = path.join(
|
|
|
15
21
|
);
|
|
16
22
|
export const ACTIVITY_STRIP_WIDTH_PADDING = 16;
|
|
17
23
|
export const ACTIVITY_STRIP_HEIGHT = 84;
|
|
24
|
+
export const ACTIVITY_STRIP_EXPANDED_HEIGHT = 252;
|
|
25
|
+
export const ACTIVITY_STRIP_ORDER_REFRESH_MS = 15_000;
|
|
26
|
+
export const ACTIVITY_STRIP_WORKSPACE_SYNC_MS = 1500;
|
|
27
|
+
export const ACTIVITY_STRIP_NIRI_ANIMATION_SETTLE_MS = 450;
|
|
18
28
|
export const ACTIVITY_STRIP_HEARTBEAT_MS = 2500;
|
|
19
29
|
export const ACTIVITY_STRIP_STALE_AFTER_MS = 12000;
|
|
20
30
|
export const ACTIVITY_STRIP_BROADCAST_TICK_MS = 1000;
|
|
@@ -33,3 +43,5 @@ export const DEFAULT_ELECTRON_CANDIDATES = [
|
|
|
33
43
|
"electron32",
|
|
34
44
|
"electron31",
|
|
35
45
|
];
|
|
46
|
+
export const ACTIVITY_STRIP_EVENT_STALL_MS = 15 * 60_000;
|
|
47
|
+
export const ACTIVITY_STRIP_FLUSH_RETRY_DELAYS_MS = [250, 750];
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
// ---
|
|
2
|
+
// summary: "declares the public TypeScript shapes shared by activity-strip runtime and JavaScript consumers"
|
|
3
|
+
// read_when:
|
|
4
|
+
// - "checking emitted declaration contracts for sessions, broker messages, telemetry, or compatibility"
|
|
5
|
+
// ---
|
|
6
|
+
|
|
1
7
|
export type SessionState = "idle" | "thinking" | "tool" | "waiting" | "success" | "error";
|
|
2
8
|
|
|
3
9
|
export interface SessionSnapshot {
|
|
4
10
|
sessionId: string;
|
|
11
|
+
publisherId: string;
|
|
5
12
|
processId: number;
|
|
6
13
|
cwd: string;
|
|
7
14
|
repoLabel: string;
|
|
@@ -14,6 +21,7 @@ export interface SessionSnapshot {
|
|
|
14
21
|
state: SessionState;
|
|
15
22
|
turnIndex: number;
|
|
16
23
|
updatedAt: number;
|
|
24
|
+
lastEventAt: number;
|
|
17
25
|
startedAt: number;
|
|
18
26
|
agentStartedAt: number | null;
|
|
19
27
|
agentActive: boolean;
|
|
@@ -65,9 +73,10 @@ export interface ActivityStripBrokerOptions {
|
|
|
65
73
|
store?: {
|
|
66
74
|
snapshot(): BrokerSnapshot;
|
|
67
75
|
upsert(session: Partial<SessionSnapshot> | Record<string, unknown>): boolean;
|
|
68
|
-
remove(sessionId: string): boolean;
|
|
76
|
+
remove(sessionId: string, publisherId?: string): boolean;
|
|
69
77
|
};
|
|
70
78
|
getRuntimeStatus?: () => ActivityStripRuntimeStatus | undefined;
|
|
79
|
+
focusSession?: (sessionId: string) => Promise<{ ok: boolean; error?: string; windowId?: number }>;
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
export interface ToolCallDescription {
|
|
@@ -95,6 +104,9 @@ export interface SessionStartContextLike {
|
|
|
95
104
|
notify?: (message: string, level?: "info" | "warning" | "error") => void;
|
|
96
105
|
editor?: (title: string, text: string) => Promise<unknown>;
|
|
97
106
|
};
|
|
107
|
+
sessionManager?: {
|
|
108
|
+
getSessionId?: () => string;
|
|
109
|
+
};
|
|
98
110
|
}
|
|
99
111
|
|
|
100
112
|
export interface BeforeAgentStartEventLike {
|
|
@@ -105,6 +117,11 @@ export interface TurnStartEventLike {
|
|
|
105
117
|
turnIndex?: number;
|
|
106
118
|
}
|
|
107
119
|
|
|
120
|
+
export interface TurnEndEventLike {
|
|
121
|
+
turnIndex?: number;
|
|
122
|
+
message?: unknown;
|
|
123
|
+
}
|
|
124
|
+
|
|
108
125
|
export interface AssistantMessageEventLike {
|
|
109
126
|
type?: string;
|
|
110
127
|
delta?: unknown;
|
|
@@ -126,6 +143,10 @@ export interface SessionTelemetryOptions {
|
|
|
126
143
|
pi?: TelemetryPiLike;
|
|
127
144
|
cwd?: string;
|
|
128
145
|
sessionName?: string;
|
|
146
|
+
transport?: {
|
|
147
|
+
publish: (session: SessionSnapshot) => Promise<unknown>;
|
|
148
|
+
remove: (session: { sessionId: string; publisherId: string }) => Promise<unknown>;
|
|
149
|
+
};
|
|
129
150
|
}
|
|
130
151
|
|
|
131
152
|
export interface ActivityStripCompatibilityReport {
|
package/src/common/contracts.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
// ---
|
|
2
|
+
// summary: "defines source TypeScript contracts for session telemetry, broker transport, and runtime compatibility"
|
|
3
|
+
// read_when:
|
|
4
|
+
// - "changing shared activity-strip types or the interfaces consumed through JSDoc imports"
|
|
5
|
+
// ---
|
|
6
|
+
|
|
1
7
|
export type SessionState = "idle" | "thinking" | "tool" | "waiting" | "success" | "error";
|
|
2
8
|
|
|
3
9
|
export interface SessionSnapshot {
|
|
4
10
|
sessionId: string;
|
|
11
|
+
publisherId: string;
|
|
5
12
|
processId: number;
|
|
6
13
|
cwd: string;
|
|
7
14
|
repoLabel: string;
|
|
@@ -14,6 +21,7 @@ export interface SessionSnapshot {
|
|
|
14
21
|
state: SessionState;
|
|
15
22
|
turnIndex: number;
|
|
16
23
|
updatedAt: number;
|
|
24
|
+
lastEventAt: number;
|
|
17
25
|
startedAt: number;
|
|
18
26
|
agentStartedAt: number | null;
|
|
19
27
|
agentActive: boolean;
|
|
@@ -65,9 +73,10 @@ export interface ActivityStripBrokerOptions {
|
|
|
65
73
|
store?: {
|
|
66
74
|
snapshot(): BrokerSnapshot;
|
|
67
75
|
upsert(session: Partial<SessionSnapshot> | Record<string, unknown>): boolean;
|
|
68
|
-
remove(sessionId: string): boolean;
|
|
76
|
+
remove(sessionId: string, publisherId?: string): boolean;
|
|
69
77
|
};
|
|
70
78
|
getRuntimeStatus?: () => ActivityStripRuntimeStatus | undefined;
|
|
79
|
+
focusSession?: (sessionId: string) => Promise<{ ok: boolean; error?: string; windowId?: number }>;
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
export interface ToolCallDescription {
|
|
@@ -95,6 +104,9 @@ export interface SessionStartContextLike {
|
|
|
95
104
|
notify?: (message: string, level?: "info" | "warning" | "error") => void;
|
|
96
105
|
editor?: (title: string, text: string) => Promise<unknown>;
|
|
97
106
|
};
|
|
107
|
+
sessionManager?: {
|
|
108
|
+
getSessionId?: () => string;
|
|
109
|
+
};
|
|
98
110
|
}
|
|
99
111
|
|
|
100
112
|
export interface BeforeAgentStartEventLike {
|
|
@@ -105,6 +117,11 @@ export interface TurnStartEventLike {
|
|
|
105
117
|
turnIndex?: number;
|
|
106
118
|
}
|
|
107
119
|
|
|
120
|
+
export interface TurnEndEventLike {
|
|
121
|
+
turnIndex?: number;
|
|
122
|
+
message?: unknown;
|
|
123
|
+
}
|
|
124
|
+
|
|
108
125
|
export interface AssistantMessageEventLike {
|
|
109
126
|
type?: string;
|
|
110
127
|
delta?: unknown;
|
|
@@ -126,6 +143,10 @@ export interface SessionTelemetryOptions {
|
|
|
126
143
|
pi?: TelemetryPiLike;
|
|
127
144
|
cwd?: string;
|
|
128
145
|
sessionName?: string;
|
|
146
|
+
transport?: {
|
|
147
|
+
publish: (session: SessionSnapshot) => Promise<unknown>;
|
|
148
|
+
remove: (session: { sessionId: string; publisherId: string }) => Promise<unknown>;
|
|
149
|
+
};
|
|
129
150
|
}
|
|
130
151
|
|
|
131
152
|
export interface ActivityStripCompatibilityReport {
|
package/src/common/electron.mjs
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// ---
|
|
2
|
+
// summary: "resolves an executable Electron binary from explicit settings, local dependencies, or PATH candidates"
|
|
3
|
+
// read_when:
|
|
4
|
+
// - "changing Electron discovery order, environment overrides, or executable checks"
|
|
5
|
+
// ---
|
|
6
|
+
|
|
1
7
|
import { constants } from "node:fs";
|
|
2
8
|
import { access } from "node:fs/promises";
|
|
3
9
|
import path from "node:path";
|
package/src/common/format.mjs
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// ---
|
|
2
|
+
// summary: "provides ANSI-safe truncation, whitespace compaction, and concise path, command, and session labels"
|
|
3
|
+
// read_when:
|
|
4
|
+
// - "changing text previews or labels displayed in activity-strip telemetry"
|
|
5
|
+
// ---
|
|
6
|
+
|
|
1
7
|
import path from "node:path";
|
|
2
8
|
|
|
3
9
|
// biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape stripping requires an ESC control character pattern.
|