toolcraft 0.0.234 → 0.0.235

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/composition.json CHANGED
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.234",
116
+ "version": "0.0.235",
117
117
  "license": "MIT"
118
118
  },
119
119
  {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  {
125
125
  "name": "toolcraft-schema",
126
- "version": "0.0.234",
126
+ "version": "0.0.235",
127
127
  "license": "MIT"
128
128
  },
129
129
  {
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.234",
116
+ "version": "0.0.235",
117
117
  "license": "MIT"
118
118
  },
119
119
  {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  {
125
125
  "name": "toolcraft-schema",
126
- "version": "0.0.234",
126
+ "version": "0.0.235",
127
127
  "license": "MIT"
128
128
  },
129
129
  {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  {
10
10
  "name": "toolcraft-schema",
11
- "version": "0.0.234",
11
+ "version": "0.0.235",
12
12
  "license": "MIT"
13
13
  }
14
14
  ]
@@ -0,0 +1,4 @@
1
+ import { ScreenBuffer } from "../buffer.js";
2
+ import type { Rect } from "../types.js";
3
+ /** Reserve fixed plan context while keeping room for the live output. */
4
+ export declare function renderContextPane(buffer: ScreenBuffer, rect: Rect, context: string[]): Rect;
@@ -0,0 +1,22 @@
1
+ import { plainTerminalText } from "../ansi.js";
2
+ import { computeVisualLines } from "./output-pane.js";
3
+ import { truncateToWidth } from "../terminal-width.js";
4
+ /** Reserve fixed plan context while keeping room for the live output. */
5
+ export function renderContextPane(buffer, rect, context) {
6
+ if (context.length === 0 || rect.width <= 0 || rect.height <= 1)
7
+ return rect;
8
+ const available = Math.max(1, Math.floor(rect.height / 2));
9
+ const entries = context.map(text => computeVisualLines([{ kind: "info", text, ts: 0 }], rect.width + 3));
10
+ const lines = entries.flat();
11
+ const visible = lines.slice(0, available);
12
+ if (lines.length > available) {
13
+ const last = visible[available - 1];
14
+ const text = entries[0].length >= available
15
+ ? truncateToWidth(`${available === 1 ? plainTerminalText(context[0]) : last.text}…`, rect.width)
16
+ : truncateToWidth(`… more plans (${context.length - 1} queued)`, rect.width);
17
+ visible[available - 1] = { ...last, text };
18
+ }
19
+ buffer.clearRect({ ...rect, height: visible.length });
20
+ visible.forEach((line, row) => buffer.putInRect(rect, row, line.text, { dim: row > 0 }));
21
+ return { ...rect, y: rect.y + visible.length, height: rect.height - visible.length };
22
+ }
@@ -7,8 +7,10 @@ export function renderCompactStatsPane(buffer, rect, stats) {
7
7
  if (rect.width <= 0 || rect.height <= 0)
8
8
  return;
9
9
  const status = formatStatus(stats.status);
10
- const metrics = `${status} · ${stats.iterationsLabel ?? "Iteration"} ${formatNumber(stats.iterations)} · ${formatElapsed(stats.elapsedMs)} · ${formatNumber(stats.tokensIn + stats.tokensOut)} tokens`;
11
- const firstLine = rect.height === 1 && stats.currentAction ? `${status} · ${stats.currentAction}` : metrics;
10
+ const progress = `${stats.iterationsLabel ?? "Iteration"} ${formatNumber(stats.iterations)}${stats.iterationsTotal === undefined ? "" : `/${formatNumber(stats.iterationsTotal)}`}`;
11
+ const primary = stats.iterationsTotal === undefined ? `${status} · ${progress}` : `${progress} · ${status}`;
12
+ const metrics = `${primary} · ${formatElapsed(stats.elapsedMs)} · ${formatNumber(stats.tokensIn + stats.tokensOut)} tokens`;
13
+ const firstLine = rect.height === 1 && stats.iterationsTotal === undefined && stats.currentAction ? `${status} · ${stats.currentAction}` : metrics;
12
14
  const messages = [firstLine, stats.currentAction ?? ""].map(plainTerminalText);
13
15
  buffer.putInRect(rect, 0, truncateToWidth(messages[0], rect.width), getStatusStyle(stats.status));
14
16
  if (rect.height > 1 && stats.currentAction !== undefined) {
@@ -23,7 +25,8 @@ export function renderStatsPane(buffer, rect, stats) {
23
25
  let lines = statsToLines(stats, rect.width);
24
26
  if (lines.length > rect.height) {
25
27
  const actions = stats.currentAction === undefined ? [] : lines.slice(9);
26
- const visibleActions = actions.slice(0, Math.max(0, rect.height - 1));
28
+ const progressLines = stats.iterationsTotal === undefined ? [] : [lines[1]];
29
+ const visibleActions = actions.slice(0, Math.max(0, rect.height - 1 - progressLines.length));
27
30
  if (visibleActions.length > 0 && visibleActions.length < actions.length) {
28
31
  const last = visibleActions[visibleActions.length - 1];
29
32
  visibleActions[visibleActions.length - 1] = {
@@ -32,9 +35,12 @@ export function renderStatsPane(buffer, rect, stats) {
32
35
  };
33
36
  }
34
37
  lines = [
35
- lines[0],
38
+ stats.iterationsTotal !== undefined && rect.height === 1
39
+ ? createKeyValueLine(formatStatus(stats.status), `${stats.iterations}/${stats.iterationsTotal}`, rect.width, getStatusStyle(stats.status))
40
+ : lines[0],
41
+ ...progressLines,
36
42
  ...visibleActions,
37
- ...lines.slice(1, 7).filter((line) => line.prefix.length > 0 || line.text.length > 0)
43
+ ...lines.slice(stats.iterationsTotal === undefined ? 1 : 2, 7).filter((line) => line.prefix.length > 0 || line.text.length > 0)
38
44
  ];
39
45
  }
40
46
  for (let row = 0; row < rect.height; row += 1) {
@@ -72,7 +78,7 @@ export function statsToLines(stats, width) {
72
78
  const iterationsLabel = plainTerminalText(stats.iterationsLabel ?? "Iteration");
73
79
  const lines = [
74
80
  createKeyValueLine("Status", formatStatus(stats.status), width, getStatusStyle(stats.status)),
75
- createKeyValueLine(iterationsLabel, formatNumber(stats.iterations), width),
81
+ createKeyValueLine(iterationsLabel, formatNumber(stats.iterations) + (stats.iterationsTotal === undefined ? "" : `/${formatNumber(stats.iterationsTotal)}`), width),
76
82
  createKeyValueLine("Elapsed", formatElapsed(stats.elapsedMs), width),
77
83
  createBlankLine(),
78
84
  createKeyValueLine("Tokens In", formatNumber(stats.tokensIn), width),
@@ -2,6 +2,7 @@ import { createRenderPerformanceMonitor, formatRenderPerformance } from "../rend
2
2
  import { createLogger } from "../components/logger.js";
3
3
  import { resolveOutputFormat } from "../internal/output-format.js";
4
4
  import { ScreenBuffer, diff } from "./buffer.js";
5
+ import { renderContextPane } from "./components/context-pane.js";
5
6
  import { renderBorder } from "./components/border.js";
6
7
  import { defaultHints, renderFooter } from "./components/footer.js";
7
8
  import { renderOutputPane } from "./components/output-pane.js";
@@ -189,6 +190,27 @@ export function createDashboard(opts = {}) {
189
190
  rightTitle: statsTitle,
190
191
  style: { dim: true }
191
192
  });
193
+ if (state.stats.context?.length) {
194
+ const contextRect = layout.summary ?? layout.leftPane;
195
+ // Context spans both panes on wide terminals.
196
+ const remaining = renderContextPane(nextBuffer, {
197
+ x: contextRect.x, y: contextRect.y, width: Math.max(0, cols - 2),
198
+ height: layout.summary ? layout.summary.height + layout.leftPane.height : layout.leftPane.height
199
+ }, state.stats.context);
200
+ const height = remaining.y - contextRect.y;
201
+ if (layout.summary) {
202
+ layout.summary.y = remaining.y;
203
+ layout.summary.height = Math.min(layout.summary.height, remaining.height);
204
+ layout.leftPane.y = layout.summary.y + layout.summary.height;
205
+ layout.leftPane.height = Math.max(0, remaining.height - layout.summary.height);
206
+ }
207
+ else {
208
+ layout.leftPane.y += height;
209
+ layout.leftPane.height -= height;
210
+ layout.rightPane.y += height;
211
+ layout.rightPane.height -= height;
212
+ }
213
+ }
192
214
  scrollOffset = renderOutputPane(nextBuffer, { ...layout.leftPane, height: Math.max(0, layout.leftPane.height - (showPerformance ? 1 : 0)) }, heldOutput ?? state.output, scrollOffset);
193
215
  if (scrollOffset === 0)
194
216
  heldOutput = undefined;
@@ -6,7 +6,7 @@ const labelControl = scenario === "label-controls" ? "\u001b]52;c;" + "HIDDEN_".
6
6
  const dashboard = createDashboard({
7
7
  title: scenario === "unicode-title" ? "Pipeline · 界界 · 👩‍💻 · é · ".repeat(3) : `Pipeline · ${scenario}${labelControl}`,
8
8
  statsTitle: scenario === "unicode-title" ? "Run · 界界 · 👩‍💻 · é" : `Run${labelControl}`,
9
- rightPaneWidth: 32,
9
+ rightPaneWidth: 44,
10
10
  hints: [
11
11
  { key: "q", label: `Quit${labelControl}` },
12
12
  { key: "↑↓", label: "Scroll" },
@@ -33,15 +33,17 @@ if (scenario !== "empty")
33
33
  dashboard.updateStats({
34
34
  status: "running",
35
35
  iterationsLabel: `Tasks${labelControl}`,
36
- iterations: 1,
36
+ iterations: scenario === "resumed" || scenario === "queue" ? 68 : 1,
37
+ iterationsTotal: scenario === "resumed" || scenario === "queue" ? 90 : 8,
38
+ context: scenario === "queue" ? ["Plan 1/3: docs/plans/improve-pipeline-task-counts-and-restart-progress.md", "Next 2/3: docs/plans/agent-conversation-recovery.md", "Next 3/3: docs/plans/界界-unicode-long-plan-title.md"] : ["Plan 1/1: docs/plans/improve-pipeline-task-counts-and-restart-progress.md"],
37
39
  tokensIn: 24000,
38
40
  tokensOut: 7000,
39
41
  elapsedMs: 65000,
40
- currentAction: "Improve streaming output (implement)"
42
+ currentAction: scenario === "resumed" || scenario === "queue" ? "Task 69/90 · Improve persisted pipeline progress · implement · step 1/2" : "Improve streaming output (implement)"
41
43
  });
42
44
  append("info", "Config · codex · model-example · docs/plans/fake-pipeline.md");
43
45
  if (scenario !== "empty")
44
- append("status", "Task 2/8 · Improve streaming output (implement)");
46
+ append("status", scenario === "resumed" || scenario === "queue" ? "Task 69/90 · Improve persisted pipeline progress (implement)" : "Task 2/8 · Improve streaming output (implement)");
45
47
  if (scenario === "empty") {
46
48
  dashboard.updateStats({
47
49
  status: "done",
@@ -118,7 +120,7 @@ else {
118
120
  }, 100);
119
121
  }
120
122
  else {
121
- timer = setInterval(() => append("info", `Streaming response ${count} · working on task 2/8`), 500);
123
+ timer = setInterval(() => append("info", `Streaming response ${count} · working on the current task`), 500);
122
124
  }
123
125
  }
124
126
  // Keep terminal state visible until QA sends q, including completed/error scenarios.
@@ -10,6 +10,8 @@ export type DashboardStats = {
10
10
  status: "idle" | "running" | "paused" | "done" | "error";
11
11
  iterations: number;
12
12
  iterationsLabel?: string;
13
+ iterationsTotal?: number;
14
+ context?: string[];
13
15
  tokensIn: number;
14
16
  tokensOut: number;
15
17
  elapsedMs: number;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-schema",
3
- "version": "0.0.234",
3
+ "version": "0.0.235",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft",
3
- "version": "0.0.234",
3
+ "version": "0.0.235",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -158,7 +158,7 @@
158
158
  "yaml"
159
159
  ],
160
160
  "optionalDependencies": {
161
- "toolcraft-schema": "0.0.234",
161
+ "toolcraft-schema": "0.0.235",
162
162
  "toolcraft-design": "*",
163
163
  "@poe-code/frontmatter": "*",
164
164
  "@poe-code/agent-mcp-config": "*",