pi-crew 0.2.12 → 0.2.13
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/package.json
CHANGED
|
@@ -204,7 +204,7 @@ export function registerTeamCommands(pi: ExtensionAPI, deps: RegisterTeamCommand
|
|
|
204
204
|
pi.registerCommand("team-run", {
|
|
205
205
|
description: "Manually start a pi-crew run (agent may also use the team tool autonomously)",
|
|
206
206
|
handler: async (args: string, ctx: ExtensionCommandContext) => {
|
|
207
|
-
const result = await handleTeamTool(parseRunArgs(args), { ...teamCommandContext(ctx), metricRegistry: deps.getMetricRegistry?.(), startForegroundRun: (runner, runId) => deps.startForegroundRun(ctx as ExtensionContext, runner, runId), abortForegroundRun: deps.abortForegroundRun, onRunStarted:
|
|
207
|
+
const result = await handleTeamTool(parseRunArgs(args), { ...teamCommandContext(ctx), metricRegistry: deps.getMetricRegistry?.(), startForegroundRun: (runner, runId) => deps.startForegroundRun(ctx as ExtensionContext, runner, runId), abortForegroundRun: deps.abortForegroundRun, onRunStarted: undefined });
|
|
208
208
|
await notifyCommandResult(ctx, commandText(result));
|
|
209
209
|
},
|
|
210
210
|
});
|
package/src/ui/crew-widget.ts
CHANGED
|
@@ -152,7 +152,13 @@ function agentStats(agent: CrewAgentRecord, liveHandle?: LiveAgentHandle): strin
|
|
|
152
152
|
const ctxPct = stats?.contextUsage?.percent;
|
|
153
153
|
if (ctxPct != null) parts.push(`${Math.round(ctxPct)}% ctx`);
|
|
154
154
|
} catch { /* ignore */ }
|
|
155
|
-
const
|
|
155
|
+
const completedMs = act.completedAtMs || 0;
|
|
156
|
+
const startedMs = act.startedAtMs || 0;
|
|
157
|
+
// Validate: startedAtMs should be within reasonable bounds (not seconds, not far future)
|
|
158
|
+
const nowMs = Date.now();
|
|
159
|
+
const isValidStarted = startedMs > 0 && startedMs < nowMs + 60000 && startedMs > nowMs - 3155692600000;
|
|
160
|
+
const isValidCompleted = completedMs === 0 || (completedMs > 0 && completedMs < nowMs + 60000);
|
|
161
|
+
const ms = (isValidCompleted ? completedMs : nowMs) - (isValidStarted ? startedMs : nowMs);
|
|
156
162
|
parts.push(`${(ms / 1000).toFixed(1)}s`);
|
|
157
163
|
} else {
|
|
158
164
|
if (agent.toolUses) parts.push(`${agent.toolUses} tools`);
|
|
@@ -423,7 +429,13 @@ export function updateCrewWidget(
|
|
|
423
429
|
if (!ctx.hasUI) return;
|
|
424
430
|
state.frame += 1;
|
|
425
431
|
const maxLines = config?.widgetMaxLines ?? MAX_LINES_DEFAULT;
|
|
426
|
-
|
|
432
|
+
// Get workspaceId from sessionManager, fallback to ownerSessionId from active runs
|
|
433
|
+
let workspaceId = ctx.sessionManager?.getSessionId?.();
|
|
434
|
+
if (!workspaceId && manifestCache) {
|
|
435
|
+
const runs = manifestCache.list(20);
|
|
436
|
+
const active = runs.find((r) => r.status === "running" || r.status === "queued");
|
|
437
|
+
if (active?.ownerSessionId) workspaceId = active.ownerSessionId;
|
|
438
|
+
}
|
|
427
439
|
const runs = activeWidgetRuns(ctx.cwd, manifestCache, snapshotCache, preloadedManifests, workspaceId);
|
|
428
440
|
const lines = buildCrewWidgetLines(ctx.cwd, state.frame, maxLines, runs, state.notificationCount ?? 0);
|
|
429
441
|
const placement = config?.widgetPlacement ?? DEFAULT_UI.widgetPlacement;
|
|
@@ -63,9 +63,17 @@ export class LiveConversationOverlay {
|
|
|
63
63
|
|
|
64
64
|
private static readonly SUMMARY_PREFIX = "\u200B"; // zero-width space as summary sentinel
|
|
65
65
|
|
|
66
|
+
private safeElapsedMs(act: typeof this.handle.activity): number {
|
|
67
|
+
const completedMs = act.completedAtMs || 0;
|
|
68
|
+
const startedMs = act.startedAtMs || 0;
|
|
69
|
+
const nowMs = Date.now();
|
|
70
|
+
const isValidStarted = startedMs > 0 && startedMs < nowMs + 60000 && startedMs > nowMs - 3155692600000;
|
|
71
|
+
const isValidCompleted = completedMs === 0 || (completedMs > 0 && completedMs < nowMs + 60000);
|
|
72
|
+
return (isValidCompleted ? completedMs : nowMs) - (isValidStarted ? startedMs : nowMs);
|
|
73
|
+
}
|
|
66
74
|
private refreshSummary(): void {
|
|
67
75
|
const act = this.handle.activity;
|
|
68
|
-
const summary = `${LiveConversationOverlay.SUMMARY_PREFIX}[${act.turnCount} turns · ${act.toolUses} tools · ${(
|
|
76
|
+
const summary = `${LiveConversationOverlay.SUMMARY_PREFIX}[${act.turnCount} turns · ${act.toolUses} tools · ${(this.safeElapsedMs(act) / 1000).toFixed(1)}s]`;
|
|
69
77
|
const lastLine = this.cachedLines[this.cachedLines.length - 1];
|
|
70
78
|
if (lastLine?.startsWith(LiveConversationOverlay.SUMMARY_PREFIX)) {
|
|
71
79
|
this.cachedLines[this.cachedLines.length - 1] = summary;
|
|
@@ -100,7 +108,7 @@ export class LiveConversationOverlay {
|
|
|
100
108
|
: iconForStatus(this.handle.status);
|
|
101
109
|
const name = this.handle.agent ?? this.handle.taskId;
|
|
102
110
|
const act = this.handle.activity;
|
|
103
|
-
const elapsed = `${(
|
|
111
|
+
const elapsed = `${(this.safeElapsedMs(act) / 1000).toFixed(1)}s`;
|
|
104
112
|
const headerParts: string[] = [];
|
|
105
113
|
if (act.maxTurns != null) headerParts.push(`turn ${act.turnCount}/${act.maxTurns}`);
|
|
106
114
|
else if (act.turnCount > 0) headerParts.push(`turn ${act.turnCount}`);
|
|
@@ -65,6 +65,8 @@ export class LiveRunSidebar {
|
|
|
65
65
|
private cachedLines: string[] = [];
|
|
66
66
|
private cachedWidth = 0;
|
|
67
67
|
private cachedSignature = "";
|
|
68
|
+
private autoCloseTimeout?: NodeJS.Timeout;
|
|
69
|
+
private hasAutoClosed = false;
|
|
68
70
|
|
|
69
71
|
constructor(input: { cwd: string; runId: string; done: Done; theme?: unknown; config?: CrewUiConfig; snapshotCache?: RunSnapshotCache }) {
|
|
70
72
|
this.cwd = input.cwd;
|
|
@@ -167,6 +169,24 @@ export class LiveRunSidebar {
|
|
|
167
169
|
lines.push(border("├", "─", "┤", w));
|
|
168
170
|
for (const entry of formatTaskGraphLines(tasks).slice(0, 6)) lines.push(line(entry, w));
|
|
169
171
|
lines.push(line("q close · /team-dashboard details", w), border("╰", "─", "╯", w));
|
|
172
|
+
// Auto-close logic: if run is terminal and no active agents, close after delay
|
|
173
|
+
const isTerminal = ["completed", "failed", "cancelled", "blocked"].includes(run.status);
|
|
174
|
+
const hasActiveAgents = agents.some((a) => a.status === "running");
|
|
175
|
+
if (isTerminal && !hasActiveAgents && !this.hasAutoClosed) {
|
|
176
|
+
const autoCloseMs = (this.config?.autoCloseDashboardMs ?? 3000);
|
|
177
|
+
if (autoCloseMs > 0) {
|
|
178
|
+
this.autoCloseTimeout = setTimeout(() => {
|
|
179
|
+
this.hasAutoClosed = true;
|
|
180
|
+
this.done(undefined);
|
|
181
|
+
}, autoCloseMs);
|
|
182
|
+
lines.push(line(`auto-close in ${Math.round(autoCloseMs / 1000)}s…`, w));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Clear timeout if conditions change
|
|
186
|
+
else if (this.autoCloseTimeout) {
|
|
187
|
+
clearTimeout(this.autoCloseTimeout);
|
|
188
|
+
this.autoCloseTimeout = undefined;
|
|
189
|
+
}
|
|
170
190
|
this.cachedLines = renderLines(lines.map((entry) => this.colorLine(entry)), w);
|
|
171
191
|
this.cachedSignature = signature;
|
|
172
192
|
this.cachedWidth = w;
|