pi-better-harness 0.1.21 → 0.1.22

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-better-background-tasks",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Pi extension for durable background shell tasks, watchers, logs, and status inspection.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -909,13 +909,13 @@ function createOverlayComponent(
909
909
  width,
910
910
  deps.truncate,
911
911
  fg,
912
- { minRows: detailRows },
912
+ { minRows: detailRows, bottomFooter: false, logTailRows },
913
913
  );
914
914
  } else {
915
915
  transcriptDetail = null;
916
916
  transcriptComponent = null;
917
917
  contentLines = mode === "detail"
918
- ? buildDetailLines(detail, width, deps.truncate, fg, { expandedSections, logTailRows, minRows: detailRows })
918
+ ? buildDetailLines(detail, width, deps.truncate, fg, { expandedSections, logTailRows, minRows: detailRows, bottomFooter: false })
919
919
  : buildListLines(overlayState, width, deps.truncate, fg);
920
920
  }
921
921
  if (mode !== "detail") return contentLines;
@@ -994,9 +994,11 @@ function buildTranscriptDetailLines(
994
994
  width: number,
995
995
  truncate: (s: string, width: number) => string,
996
996
  fg: (color: string, value: string) => string,
997
- options: { minRows?: number } = {},
997
+ options: { minRows?: number; bottomFooter?: boolean; logTailRows?: number } = {},
998
998
  ): string[] {
999
999
  const actions = [...(detail.footerActions ?? ["x close"]), "Esc close"].join(" · ");
1000
+ const tailRows = options.logTailRows ?? DEFAULT_LOG_TAIL_ROWS;
1001
+ const shownTranscriptLines = transcriptLines.length ? transcriptLines.slice(-tailRows) : [" (no transcript yet)"];
1000
1002
  const lines: string[] = [
1001
1003
  fg("accent", rule(detail.title, width)),
1002
1004
  dim(` ← main · ${actions}`, fg),
@@ -1005,10 +1007,11 @@ function buildTranscriptDetailLines(
1005
1007
  ];
1006
1008
  if (detail.subtitle) lines.push(` summary ${detail.subtitle}`);
1007
1009
  for (const item of detail.metadata) lines.push(` ${item.label.padEnd(8, " ").slice(0, 8)} ${item.value}`);
1008
- lines.push("", dim(section("transcript", width), fg));
1010
+ lines.push("", dim(section(`transcript · latest ${tailRows} rows`, width), fg));
1009
1011
  if (detail.transcriptDiagnostic) lines.push(` ${dim(detail.transcriptDiagnostic, fg)}`);
1010
- lines.push(...(transcriptLines.length ? transcriptLines : [" (no transcript yet)"]));
1012
+ lines.push(...shownTranscriptLines);
1011
1013
  lines.push("");
1014
+ if (options.bottomFooter === false) return lines.map((line) => safeTruncate(line, width, truncate));
1012
1015
  const footerLines = [dim(` ← main · ${actions}`, fg), dim(rule("", width), fg)];
1013
1016
  padBeforeFooter(lines, footerLines.length, options.minRows);
1014
1017
  lines.push(...footerLines);
@@ -1092,10 +1095,11 @@ function buildDetailLines(
1092
1095
  width: number,
1093
1096
  truncate: (s: string, width: number) => string,
1094
1097
  fg: (color: string, value: string) => string,
1095
- options: { expandedSections?: Set<string>; logTailRows?: number; minRows?: number } = {},
1098
+ options: { expandedSections?: Set<string>; logTailRows?: number; minRows?: number; bottomFooter?: boolean } = {},
1096
1099
  ): string[] {
1097
1100
  if (!detail) {
1098
1101
  const lines = [rule("Work unavailable", width), dim(" ← back · Esc close", fg), ""];
1102
+ if (options.bottomFooter === false) return lines.map((line) => safeTruncate(line, width, truncate));
1099
1103
  const footerLines = [dim(rule("", width), fg)];
1100
1104
  padBeforeFooter(lines, footerLines.length, options.minRows);
1101
1105
  lines.push(...footerLines);
@@ -1149,14 +1153,17 @@ function buildDetailLines(
1149
1153
  for (const raw of shown) lines.push(raw ? ` ${raw}` : " ");
1150
1154
  }
1151
1155
  } else {
1152
- const evidenceLabel = /log/i.test(detail.evidence.label) ? `${detail.evidence.label} · latest ${tailRows} rows` : detail.evidence.label;
1156
+ const tailEvidence = isTailEvidence(detail);
1157
+ const evidenceLabel = tailEvidence ? `${detail.evidence.label} · latest ${tailRows} rows` : detail.evidence.label;
1153
1158
  lines.push(dim(section(evidenceLabel, width), fg));
1154
1159
  const wrapped = /log/i.test(detail.evidence.label)
1155
1160
  ? wrapLogText(body, width - 6)
1156
- : body.split(/\r?\n/);
1157
- for (const raw of wrapped) lines.push(raw ? ` ${raw}` : " ");
1161
+ : wrapEvidenceText(body, width - 6);
1162
+ const shown = tailEvidence ? wrapped.slice(-tailRows) : wrapped;
1163
+ for (const raw of shown) lines.push(raw ? ` ${raw}` : " ");
1158
1164
  }
1159
1165
  lines.push("");
1166
+ if (options.bottomFooter === false) return lines.map((line) => safeTruncate(line, width, truncate));
1160
1167
  const footerLines = [dim(` ← back · ${actions}`, fg), dim(rule("", width), fg)];
1161
1168
  padBeforeFooter(lines, footerLines.length, options.minRows);
1162
1169
  lines.push(...footerLines);
@@ -1182,7 +1189,11 @@ function applyDefaultExpandedSections(detail: BackgroundWorkDetail | null, expan
1182
1189
  }
1183
1190
 
1184
1191
  function isFoldableEvidence(detail: BackgroundWorkDetail): boolean {
1185
- return !/log/i.test(detail.evidence.label);
1192
+ return !isTailEvidence(detail);
1193
+ }
1194
+
1195
+ function isTailEvidence(detail: BackgroundWorkDetail): boolean {
1196
+ return /log|transcript/i.test(detail.evidence.label);
1186
1197
  }
1187
1198
 
1188
1199
  function sectionHeader(label: string, width: number): string {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-better-subagents",
3
- "version": "0.1.20",
3
+ "version": "0.1.21",
4
4
  "description": "Pi extension for detached, sandboxed subagent runs that keep the foreground session free.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -909,13 +909,13 @@ function createOverlayComponent(
909
909
  width,
910
910
  deps.truncate,
911
911
  fg,
912
- { minRows: detailRows },
912
+ { minRows: detailRows, bottomFooter: false, logTailRows },
913
913
  );
914
914
  } else {
915
915
  transcriptDetail = null;
916
916
  transcriptComponent = null;
917
917
  contentLines = mode === "detail"
918
- ? buildDetailLines(detail, width, deps.truncate, fg, { expandedSections, logTailRows, minRows: detailRows })
918
+ ? buildDetailLines(detail, width, deps.truncate, fg, { expandedSections, logTailRows, minRows: detailRows, bottomFooter: false })
919
919
  : buildListLines(overlayState, width, deps.truncate, fg);
920
920
  }
921
921
  if (mode !== "detail") return contentLines;
@@ -994,9 +994,11 @@ function buildTranscriptDetailLines(
994
994
  width: number,
995
995
  truncate: (s: string, width: number) => string,
996
996
  fg: (color: string, value: string) => string,
997
- options: { minRows?: number } = {},
997
+ options: { minRows?: number; bottomFooter?: boolean; logTailRows?: number } = {},
998
998
  ): string[] {
999
999
  const actions = [...(detail.footerActions ?? ["x close"]), "Esc close"].join(" · ");
1000
+ const tailRows = options.logTailRows ?? DEFAULT_LOG_TAIL_ROWS;
1001
+ const shownTranscriptLines = transcriptLines.length ? transcriptLines.slice(-tailRows) : [" (no transcript yet)"];
1000
1002
  const lines: string[] = [
1001
1003
  fg("accent", rule(detail.title, width)),
1002
1004
  dim(` ← main · ${actions}`, fg),
@@ -1005,10 +1007,11 @@ function buildTranscriptDetailLines(
1005
1007
  ];
1006
1008
  if (detail.subtitle) lines.push(` summary ${detail.subtitle}`);
1007
1009
  for (const item of detail.metadata) lines.push(` ${item.label.padEnd(8, " ").slice(0, 8)} ${item.value}`);
1008
- lines.push("", dim(section("transcript", width), fg));
1010
+ lines.push("", dim(section(`transcript · latest ${tailRows} rows`, width), fg));
1009
1011
  if (detail.transcriptDiagnostic) lines.push(` ${dim(detail.transcriptDiagnostic, fg)}`);
1010
- lines.push(...(transcriptLines.length ? transcriptLines : [" (no transcript yet)"]));
1012
+ lines.push(...shownTranscriptLines);
1011
1013
  lines.push("");
1014
+ if (options.bottomFooter === false) return lines.map((line) => safeTruncate(line, width, truncate));
1012
1015
  const footerLines = [dim(` ← main · ${actions}`, fg), dim(rule("", width), fg)];
1013
1016
  padBeforeFooter(lines, footerLines.length, options.minRows);
1014
1017
  lines.push(...footerLines);
@@ -1092,10 +1095,11 @@ function buildDetailLines(
1092
1095
  width: number,
1093
1096
  truncate: (s: string, width: number) => string,
1094
1097
  fg: (color: string, value: string) => string,
1095
- options: { expandedSections?: Set<string>; logTailRows?: number; minRows?: number } = {},
1098
+ options: { expandedSections?: Set<string>; logTailRows?: number; minRows?: number; bottomFooter?: boolean } = {},
1096
1099
  ): string[] {
1097
1100
  if (!detail) {
1098
1101
  const lines = [rule("Work unavailable", width), dim(" ← back · Esc close", fg), ""];
1102
+ if (options.bottomFooter === false) return lines.map((line) => safeTruncate(line, width, truncate));
1099
1103
  const footerLines = [dim(rule("", width), fg)];
1100
1104
  padBeforeFooter(lines, footerLines.length, options.minRows);
1101
1105
  lines.push(...footerLines);
@@ -1149,14 +1153,17 @@ function buildDetailLines(
1149
1153
  for (const raw of shown) lines.push(raw ? ` ${raw}` : " ");
1150
1154
  }
1151
1155
  } else {
1152
- const evidenceLabel = /log/i.test(detail.evidence.label) ? `${detail.evidence.label} · latest ${tailRows} rows` : detail.evidence.label;
1156
+ const tailEvidence = isTailEvidence(detail);
1157
+ const evidenceLabel = tailEvidence ? `${detail.evidence.label} · latest ${tailRows} rows` : detail.evidence.label;
1153
1158
  lines.push(dim(section(evidenceLabel, width), fg));
1154
1159
  const wrapped = /log/i.test(detail.evidence.label)
1155
1160
  ? wrapLogText(body, width - 6)
1156
- : body.split(/\r?\n/);
1157
- for (const raw of wrapped) lines.push(raw ? ` ${raw}` : " ");
1161
+ : wrapEvidenceText(body, width - 6);
1162
+ const shown = tailEvidence ? wrapped.slice(-tailRows) : wrapped;
1163
+ for (const raw of shown) lines.push(raw ? ` ${raw}` : " ");
1158
1164
  }
1159
1165
  lines.push("");
1166
+ if (options.bottomFooter === false) return lines.map((line) => safeTruncate(line, width, truncate));
1160
1167
  const footerLines = [dim(` ← back · ${actions}`, fg), dim(rule("", width), fg)];
1161
1168
  padBeforeFooter(lines, footerLines.length, options.minRows);
1162
1169
  lines.push(...footerLines);
@@ -1182,7 +1189,11 @@ function applyDefaultExpandedSections(detail: BackgroundWorkDetail | null, expan
1182
1189
  }
1183
1190
 
1184
1191
  function isFoldableEvidence(detail: BackgroundWorkDetail): boolean {
1185
- return !/log/i.test(detail.evidence.label);
1192
+ return !isTailEvidence(detail);
1193
+ }
1194
+
1195
+ function isTailEvidence(detail: BackgroundWorkDetail): boolean {
1196
+ return /log|transcript/i.test(detail.evidence.label);
1186
1197
  }
1187
1198
 
1188
1199
  function sectionHeader(label: string, width: number): string {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-better-harness",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "description": "Pi extension bundle for subagents, durable background tasks, and goal tracking.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -43,9 +43,9 @@
43
43
  "test": "node --test test/*.test.mjs"
44
44
  },
45
45
  "dependencies": {
46
- "pi-better-background-tasks": "0.2.2",
46
+ "pi-better-background-tasks": "0.2.3",
47
47
  "pi-better-goal": "0.1.21",
48
- "pi-better-subagents": "0.1.20"
48
+ "pi-better-subagents": "0.1.21"
49
49
  },
50
50
  "bundledDependencies": [
51
51
  "pi-better-background-tasks",