ac-teams 0.0.16 → 0.0.17
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 +1 -1
- package/src/panel.ts +21 -9
- package/src/render.ts +5 -3
package/package.json
CHANGED
package/src/panel.ts
CHANGED
|
@@ -65,6 +65,7 @@ export async function showTeamsPanel(ctx: ExtensionContext, host: PanelHost): Pr
|
|
|
65
65
|
return clipped + " ".repeat(Math.max(0, width - visibleWidth(clipped)));
|
|
66
66
|
};
|
|
67
67
|
const heading = (text: string) => theme.bold(fg("text", text));
|
|
68
|
+
const tableHeader = (text: string) => theme.bold(theme.underline(fg("accent", text)));
|
|
68
69
|
const label = (key: string, value: string) => fg("muted", key.padEnd(9) + " ") + value;
|
|
69
70
|
const wrap = (lines: string[], width: number) => lines.flatMap(line => wrapTextWithAnsi(line, Math.max(1, width)));
|
|
70
71
|
const editor = new Editor(tui, {
|
|
@@ -159,7 +160,8 @@ export async function showTeamsPanel(ctx: ExtensionContext, host: PanelHost): Pr
|
|
|
159
160
|
else if (selected.right >= columnScroll + width) columnScroll = selected.right - width + 1;
|
|
160
161
|
columnScroll = Math.max(0, Math.min(columnScroll, Math.max(0, art.width - width)));
|
|
161
162
|
const rows = art.styled.map((spans, y) => {
|
|
162
|
-
|
|
163
|
+
const row = spans.map(span => fg(span.cls === "border" || span.cls === "edge" ? "dim" : "text", span.text)).join("");
|
|
164
|
+
const replacements: { left: number; right: number; text: string }[] = [];
|
|
163
165
|
for (const task of tasks) {
|
|
164
166
|
const box = bounds.get(task.id);
|
|
165
167
|
if (!box || y < box.top || y > box.bottom) continue;
|
|
@@ -174,10 +176,18 @@ export async function showTeamsPanel(ctx: ExtensionContext, host: PanelHost): Pr
|
|
|
174
176
|
// The selected box keeps its status colour but gets a heavy border and bold text, so selection never competes with status.
|
|
175
177
|
const edge = (part: string) => statusText(task, active ? part.replace(/[┌┐└┘─│┬┴]/g, ch => ({ "┌": "┏", "┐": "┓", "└": "┗", "┘": "┛", "─": "━", "│": "┃", "┬": "┯", "┴": "┷" })[ch]!) : part);
|
|
176
178
|
const styled = border ? edge(text) : edge("│") + (active ? theme.bold(interior) : interior) + edge("│");
|
|
177
|
-
|
|
179
|
+
replacements.push({ left: box.left, right: box.right, text: styled });
|
|
178
180
|
}
|
|
181
|
+
// Slice the original row once per gap; re-slicing styled replacements multiplies ANSI codes.
|
|
182
|
+
let column = 0;
|
|
183
|
+
const parts = replacements.sort((a, b) => a.left - b.left).flatMap(box => {
|
|
184
|
+
const gap = sliceByColumn(row, column, box.left - column);
|
|
185
|
+
column = box.right + 1;
|
|
186
|
+
return [gap, box.text];
|
|
187
|
+
});
|
|
188
|
+
parts.push(sliceByColumn(row, column, art.width - column));
|
|
179
189
|
const indent = " ".repeat(Math.max(0, Math.floor((width - art.width) / 2)));
|
|
180
|
-
return indent + sliceByColumn(
|
|
190
|
+
return indent + sliceByColumn(parts.join(""), columnScroll, width);
|
|
181
191
|
});
|
|
182
192
|
return { rows, selectedRow: selected.top, selectedHeight: selected.bottom - selected.top + 1, width: art.width };
|
|
183
193
|
}
|
|
@@ -204,11 +214,13 @@ export async function showTeamsPanel(ctx: ExtensionContext, host: PanelHost): Pr
|
|
|
204
214
|
let selectedHeight = 1, graphWidth = 0;
|
|
205
215
|
if (tab === 0) {
|
|
206
216
|
const graphData = graph ? graphLines(leftWidth) : undefined;
|
|
207
|
-
|
|
217
|
+
const titleWidth = Math.max(1, leftWidth - 12);
|
|
218
|
+
left = graphData ? graphData.rows : tasks.length ? [tableHeader(` ${pad("Task", titleWidth)} State`), "",
|
|
208
219
|
...tasks.map((task, index) => {
|
|
209
|
-
const
|
|
210
|
-
const body = fg(taskStatus(task) === "Done" ? "dim" : "text",
|
|
211
|
-
return (
|
|
220
|
+
const selected = index === taskIndex;
|
|
221
|
+
const body = fg(taskStatus(task) === "Done" ? "dim" : "text", pad(taskTitle(task.id), titleWidth));
|
|
222
|
+
return fg(selected ? "accent" : "dim", `${selected ? "●" : " "} `)
|
|
223
|
+
+ (selected ? theme.bold(body) : body) + " " + stateLabel(task);
|
|
212
224
|
})] : [heading("No tasks yet"), "N Request a task from Main"];
|
|
213
225
|
selectedRow = graphData ? graphData.selectedRow : taskIndex + 2;
|
|
214
226
|
selectedHeight = graphData?.selectedHeight ?? 1;
|
|
@@ -231,7 +243,7 @@ export async function showTeamsPanel(ctx: ExtensionContext, host: PanelHost): Pr
|
|
|
231
243
|
const nameExtra = Math.min(spare, Math.max(0, ...ids.map(id => visibleWidth(name(id)) - nameWidth)));
|
|
232
244
|
const gap = " ".repeat(4 + Math.floor((spare - nameExtra) / gaps));
|
|
233
245
|
nameWidth += nameExtra + (spare - nameExtra) % gaps;
|
|
234
|
-
left = [
|
|
246
|
+
left = [tableHeader(` ${pad("Member", nameWidth)}${gap}${pad("State", sessionWidth)}`
|
|
235
247
|
+ (showTasks ? `${gap}${pad("Done", tasksWidth)}` : "") + (showDirectory ? `${gap}Directory` : "")), ...ids.map((id, index) => {
|
|
236
248
|
const member = snapshot.members.find(member => member.id === id);
|
|
237
249
|
const selected = index === memberIndex;
|
|
@@ -254,7 +266,7 @@ export async function showTeamsPanel(ctx: ExtensionContext, host: PanelHost): Pr
|
|
|
254
266
|
const fromWidth = Math.min(16, Math.max(4, ...events.map(event => visibleWidth(name(event.from)))));
|
|
255
267
|
const taskWidth = Math.min(5, Math.max(4, ...events.map(event => event.task ? visibleWidth(taskRef(event.task)) : 0)));
|
|
256
268
|
const summaryWidth = Math.max(1, leftWidth - (2 + fromWidth + 2 + 7 + 2 + 2 + taskWidth + 2 + 5));
|
|
257
|
-
left = events.length ? [
|
|
269
|
+
left = events.length ? [tableHeader(` ${pad("From", fromWidth)} ${pad("Kind", 7)} ${pad("Summary", summaryWidth)} ${pad("Task", taskWidth)} Time`),
|
|
258
270
|
...events.map((event, index) => {
|
|
259
271
|
const selected = index === eventIndex;
|
|
260
272
|
const from = pad(name(event.from), fromWidth), summary = pad(headline(event), summaryWidth);
|
package/src/render.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { stripVTControlCharacters } from "node:util";
|
|
2
2
|
import { keyHint, type MessageRenderer, type Theme, type ToolRenderers } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import { Container, Text, TruncatedText, truncateToWidth, visibleWidth, wrapTextWithAnsi, type Component } from "@earendil-works/pi-tui";
|
|
3
|
+
import { Box, Container, Text, TruncatedText, truncateToWidth, visibleWidth, wrapTextWithAnsi, type Component } from "@earendil-works/pi-tui";
|
|
4
4
|
|
|
5
5
|
export const cleanText = (text: string): string => stripVTControlCharacters(text).replaceAll("\t", " ").replace(/[\x00-\x08\x0b-\x1f\x7f-\x9f]/g, "");
|
|
6
6
|
const inline = (value: unknown) => cleanText(String(value)).replace(/[\n\r\t]/g, " ");
|
|
@@ -125,7 +125,7 @@ export function teamToolRenderers(name: string, getLabels: MemberLabels = defaul
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
export function teamMessageRenderer(getLabels: MemberLabels = defaultLabels): MessageRenderer {
|
|
128
|
-
return (message, { expanded }, theme) => {
|
|
128
|
+
return (message, { expanded, outputPad }, theme) => {
|
|
129
129
|
const details = message.details as { through?: number; messages?: { from: string; summary: string; recipients: string[]; task?: string; kind?: string }[] } | undefined;
|
|
130
130
|
const posts = details?.messages ?? [], recent = posts.at(-1);
|
|
131
131
|
const more = posts.length > 1 ? ` (+${posts.length - 1} more)` : "";
|
|
@@ -134,7 +134,9 @@ export function teamMessageRenderer(getLabels: MemberLabels = defaultLabels): Me
|
|
|
134
134
|
// Lead with what happened: "count-a completed #1 Count lines · 37 lines", or "count-a → Main · #1 … · question".
|
|
135
135
|
const what = recent && (recent.kind === "outcome" && recent.task ? `${name(recent.from)} completed ${name(recent.task)}` : `${name(recent.from)} → ${recent.recipients.map(name).join(", ")}${recent.task ? ` · ${name(recent.task)}` : ""}`);
|
|
136
136
|
const preview = recent ? `${what} · ${recent.summary.split("\n")[0]}${more}` : `Updates through ${details?.through ?? "unknown"}`;
|
|
137
|
-
|
|
137
|
+
const box = new Box(outputPad, 0);
|
|
138
|
+
box.addChild(entry("ac-teams", details ?? { content: message.content }, expanded, theme, false, preview));
|
|
139
|
+
return box;
|
|
138
140
|
};
|
|
139
141
|
}
|
|
140
142
|
|