@astralyn/pi 0.82.4 → 0.82.6
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/CHANGELOG.md +52 -0
- package/dist/cli/project-trust.d.ts.map +1 -1
- package/dist/cli/project-trust.js +4 -1
- package/dist/cli/project-trust.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +4 -22
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/extensions/index.d.ts +2 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +2 -3
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +37 -5
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +11 -0
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts +3 -13
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +6 -36
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/extensions/plan/constants.d.ts +11 -2
- package/dist/extensions/plan/constants.d.ts.map +1 -1
- package/dist/extensions/plan/constants.js +14 -2
- package/dist/extensions/plan/constants.js.map +1 -1
- package/dist/extensions/plan/index.d.ts +0 -18
- package/dist/extensions/plan/index.d.ts.map +1 -1
- package/dist/extensions/plan/index.js +35 -3
- package/dist/extensions/plan/index.js.map +1 -1
- package/dist/extensions/plan/view.d.ts +36 -0
- package/dist/extensions/plan/view.d.ts.map +1 -0
- package/dist/extensions/plan/view.js +74 -0
- package/dist/extensions/plan/view.js.map +1 -0
- package/dist/extensions/question/dialog.d.ts +3 -1
- package/dist/extensions/question/dialog.d.ts.map +1 -1
- package/dist/extensions/question/dialog.js +106 -52
- package/dist/extensions/question/dialog.js.map +1 -1
- package/dist/extensions/question/index.d.ts.map +1 -1
- package/dist/extensions/question/index.js +2 -2
- package/dist/extensions/question/index.js.map +1 -1
- package/dist/extensions/question/render-cache.d.ts +9 -0
- package/dist/extensions/question/render-cache.d.ts.map +1 -1
- package/dist/extensions/question/render-cache.js +22 -0
- package/dist/extensions/question/render-cache.js.map +1 -1
- package/dist/extensions/question/results.d.ts.map +1 -1
- package/dist/extensions/question/results.js +6 -1
- package/dist/extensions/question/results.js.map +1 -1
- package/dist/extensions/question/schema.d.ts +4 -0
- package/dist/extensions/question/schema.d.ts.map +1 -1
- package/dist/extensions/question/schema.js +19 -28
- package/dist/extensions/question/schema.js.map +1 -1
- package/dist/extensions/question/types.d.ts +1 -1
- package/dist/extensions/question/types.d.ts.map +1 -1
- package/dist/extensions/question/types.js.map +1 -1
- package/dist/extensions/router/stream.d.ts.map +1 -1
- package/dist/extensions/router/stream.js +44 -0
- package/dist/extensions/router/stream.js.map +1 -1
- package/dist/extensions/subagent/activity.d.ts.map +1 -1
- package/dist/extensions/subagent/activity.js +25 -4
- package/dist/extensions/subagent/activity.js.map +1 -1
- package/dist/extensions/subagent/agents.d.ts.map +1 -1
- package/dist/extensions/subagent/agents.js +12 -6
- package/dist/extensions/subagent/agents.js.map +1 -1
- package/dist/extensions/subagent/constants.d.ts +1 -1
- package/dist/extensions/subagent/constants.d.ts.map +1 -1
- package/dist/extensions/subagent/constants.js +3 -2
- package/dist/extensions/subagent/constants.js.map +1 -1
- package/dist/extensions/subagent/index.d.ts.map +1 -1
- package/dist/extensions/subagent/index.js +14 -0
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/subagent/render.d.ts.map +1 -1
- package/dist/extensions/subagent/render.js +243 -116
- package/dist/extensions/subagent/render.js.map +1 -1
- package/dist/extensions/subagent/resolve.d.ts.map +1 -1
- package/dist/extensions/subagent/resolve.js +13 -9
- package/dist/extensions/subagent/resolve.js.map +1 -1
- package/dist/extensions/subagent/runner.d.ts +1 -1
- package/dist/extensions/subagent/runner.d.ts.map +1 -1
- package/dist/extensions/subagent/runner.js +9 -3
- package/dist/extensions/subagent/runner.js.map +1 -1
- package/dist/extensions/subagent/schema.d.ts.map +1 -1
- package/dist/extensions/subagent/schema.js +4 -4
- package/dist/extensions/subagent/schema.js.map +1 -1
- package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
- package/dist/extensions/subagent/sdk-runner.js +5 -0
- package/dist/extensions/subagent/sdk-runner.js.map +1 -1
- package/dist/extensions/subagent/types.d.ts +7 -0
- package/dist/extensions/subagent/types.d.ts.map +1 -1
- package/dist/extensions/subagent/types.js.map +1 -1
- package/dist/extensions/todo/constants.d.ts +17 -6
- package/dist/extensions/todo/constants.d.ts.map +1 -1
- package/dist/extensions/todo/constants.js +47 -9
- package/dist/extensions/todo/constants.js.map +1 -1
- package/dist/extensions/todo/index.d.ts +1 -15
- package/dist/extensions/todo/index.d.ts.map +1 -1
- package/dist/extensions/todo/index.js +35 -4
- package/dist/extensions/todo/index.js.map +1 -1
- package/dist/extensions/todo/schema.d.ts +59 -7
- package/dist/extensions/todo/schema.d.ts.map +1 -1
- package/dist/extensions/todo/schema.js +72 -12
- package/dist/extensions/todo/schema.js.map +1 -1
- package/dist/extensions/todo/state.d.ts +20 -5
- package/dist/extensions/todo/state.d.ts.map +1 -1
- package/dist/extensions/todo/state.js +1016 -134
- package/dist/extensions/todo/state.js.map +1 -1
- package/dist/extensions/todo/view.d.ts +16 -1
- package/dist/extensions/todo/view.d.ts.map +1 -1
- package/dist/extensions/todo/view.js +293 -7
- package/dist/extensions/todo/view.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +6 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +14 -6
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +6 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +41 -2
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +8 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/coalescing-terminal.d.ts +71 -17
- package/dist/utils/coalescing-terminal.d.ts.map +1 -1
- package/dist/utils/coalescing-terminal.js +136 -31
- package/dist/utils/coalescing-terminal.js.map +1 -1
- package/docs/bundled/extensions/plan.md +6 -4
- package/docs/bundled/extensions/question.md +9 -7
- package/docs/bundled/extensions/subagent.md +4 -4
- package/docs/bundled/extensions/todo.md +9 -5
- package/docs/bundled/tool-presentation.md +1 -1
- package/docs/extensions.md +14 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/utils/output-decoder.d.ts +0 -52
- package/dist/utils/output-decoder.d.ts.map +0 -1
- package/dist/utils/output-decoder.js +0 -134
- package/dist/utils/output-decoder.js.map +0 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { truncateToWidth } from "@earendil-works/pi-tui";
|
|
2
|
+
import { LIST_DISPLAY_MAX_ITEMS } from "./constants.js";
|
|
3
|
+
import { TODO_DETAILS_SCHEMA_VERSION, } from "./schema.js";
|
|
2
4
|
import { unresolvedDependencyIds } from "./state.js";
|
|
3
5
|
export const STATUS_MARK = {
|
|
4
6
|
pending: "[ ]",
|
|
@@ -20,12 +22,16 @@ export function hasVisibleOverlayItems(state, hiddenCompleted) {
|
|
|
20
22
|
return visibleTodos(state).some((item) => item.status !== "completed" || !hiddenCompleted.has(item.id));
|
|
21
23
|
}
|
|
22
24
|
function todoCounts(items) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
const counts = { total: items.length, pending: 0, inProgress: 0, completed: 0 };
|
|
26
|
+
for (const item of items) {
|
|
27
|
+
if (item.status === "pending")
|
|
28
|
+
counts.pending++;
|
|
29
|
+
else if (item.status === "in_progress")
|
|
30
|
+
counts.inProgress++;
|
|
31
|
+
else if (item.status === "completed")
|
|
32
|
+
counts.completed++;
|
|
33
|
+
}
|
|
34
|
+
return counts;
|
|
29
35
|
}
|
|
30
36
|
export function renderOverlayLines(state, theme, width, hiddenCompleted) {
|
|
31
37
|
const allVisible = visibleTodos(state);
|
|
@@ -96,24 +102,304 @@ function formatOverlayItem(item, state, theme, showId) {
|
|
|
96
102
|
}
|
|
97
103
|
return text;
|
|
98
104
|
}
|
|
105
|
+
const EDGE_PARAMS = ["blockedBy", "addBlockedBy", "removeBlockedBy", "addBlocks", "removeBlocks"];
|
|
106
|
+
function callText(value) {
|
|
107
|
+
return typeof value === "string" ? value.trim() : "";
|
|
108
|
+
}
|
|
109
|
+
function callId(value) {
|
|
110
|
+
return typeof value === "number" && Number.isInteger(value) ? value : undefined;
|
|
111
|
+
}
|
|
112
|
+
function callIds(value) {
|
|
113
|
+
return Array.isArray(value) ? value.filter((entry) => typeof entry === "number") : [];
|
|
114
|
+
}
|
|
115
|
+
function callArrayLength(value) {
|
|
116
|
+
return Array.isArray(value) ? value.length : undefined;
|
|
117
|
+
}
|
|
118
|
+
function callBatchSubjects(value) {
|
|
119
|
+
if (!Array.isArray(value))
|
|
120
|
+
return "";
|
|
121
|
+
const subjects = [];
|
|
122
|
+
for (const item of value.slice(0, 3)) {
|
|
123
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
124
|
+
continue;
|
|
125
|
+
const subject = callText(item.subject);
|
|
126
|
+
if (subject)
|
|
127
|
+
subjects.push(subject);
|
|
128
|
+
}
|
|
129
|
+
return subjects.join("; ");
|
|
130
|
+
}
|
|
131
|
+
function callNonNegativeInteger(value) {
|
|
132
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : undefined;
|
|
133
|
+
}
|
|
134
|
+
function isTodoStatus(value) {
|
|
135
|
+
return Object.hasOwn(STATUS_MARK, value);
|
|
136
|
+
}
|
|
137
|
+
function formatCallHeadline(args, theme) {
|
|
138
|
+
const action = callText(args?.action);
|
|
139
|
+
const parts = [theme.fg("toolTitle", theme.bold(action ? `todo ${action}` : "todo"))];
|
|
140
|
+
if (action === "create_many") {
|
|
141
|
+
const count = callArrayLength(args?.items);
|
|
142
|
+
if (count !== undefined)
|
|
143
|
+
parts.push(theme.fg("dim", `${count} tasks`));
|
|
144
|
+
}
|
|
145
|
+
const id = callId(args?.id);
|
|
146
|
+
if (id !== undefined)
|
|
147
|
+
parts.push(theme.fg("accent", `#${id}`));
|
|
148
|
+
const status = callText(args?.status);
|
|
149
|
+
if (status && isTodoStatus(status))
|
|
150
|
+
parts.push(theme.fg(STATUS_COLOR[status], status));
|
|
151
|
+
const subject = callText(args?.subject);
|
|
152
|
+
if (subject)
|
|
153
|
+
parts.push(theme.fg("text", subject));
|
|
154
|
+
// Dependency-only updates would otherwise render as a bare `todo update #3`.
|
|
155
|
+
const hasEdgeChange = EDGE_PARAMS.some((key) => callIds(args?.[key]).length > 0);
|
|
156
|
+
if (!status && !subject && hasEdgeChange)
|
|
157
|
+
parts.push(theme.fg("dim", "dependencies"));
|
|
158
|
+
return parts.join(" ");
|
|
159
|
+
}
|
|
160
|
+
function formatCallDetails(args, theme) {
|
|
161
|
+
const lines = [];
|
|
162
|
+
const push = (label, value) => {
|
|
163
|
+
if (value)
|
|
164
|
+
lines.push(theme.fg("dim", `${label}: ${value}`));
|
|
165
|
+
};
|
|
166
|
+
const action = callText(args?.action);
|
|
167
|
+
if (action === "create_many") {
|
|
168
|
+
const count = callArrayLength(args?.items);
|
|
169
|
+
if (count !== undefined) {
|
|
170
|
+
const subjects = callBatchSubjects(args?.items);
|
|
171
|
+
push("batch", `${count} tasks${subjects ? ` (${subjects})` : ""}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
push("description", callText(args?.description));
|
|
175
|
+
push("activeForm", callText(args?.activeForm));
|
|
176
|
+
push("owner", callText(args?.owner));
|
|
177
|
+
for (const key of EDGE_PARAMS) {
|
|
178
|
+
const ids = callIds(args?.[key]);
|
|
179
|
+
if (ids.length)
|
|
180
|
+
push(key, ids.map((id) => `#${id}`).join(","));
|
|
181
|
+
}
|
|
182
|
+
if (args?.includeDeleted === true)
|
|
183
|
+
push("includeDeleted", "true");
|
|
184
|
+
const limit = callId(args?.limit);
|
|
185
|
+
if (limit !== undefined)
|
|
186
|
+
push("limit", String(limit));
|
|
187
|
+
const afterId = callId(args?.afterId);
|
|
188
|
+
if (afterId !== undefined)
|
|
189
|
+
push("afterId", String(afterId));
|
|
190
|
+
push("query", callText(args?.query));
|
|
191
|
+
if (args?.unblockedOnly === true)
|
|
192
|
+
push("unblockedOnly", "true");
|
|
193
|
+
if (args?.confirm === true)
|
|
194
|
+
push("confirm", "true");
|
|
195
|
+
const expectedCount = callNonNegativeInteger(args?.expectedCount);
|
|
196
|
+
if (expectedCount !== undefined)
|
|
197
|
+
push("expectedCount", String(expectedCount));
|
|
198
|
+
const metadata = args?.metadata;
|
|
199
|
+
if (metadata && typeof metadata === "object")
|
|
200
|
+
push("metadata", Object.keys(metadata).join(","));
|
|
201
|
+
return lines;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* One-line call summary when collapsed; the same headline plus the parameters
|
|
205
|
+
* the result never echoes (description, activeForm, dependencies) when expanded.
|
|
206
|
+
*/
|
|
207
|
+
export function formatTodoCall(args, theme, expanded) {
|
|
208
|
+
const headline = formatCallHeadline(args, theme);
|
|
209
|
+
if (!expanded)
|
|
210
|
+
return headline;
|
|
211
|
+
return [headline, ...formatCallDetails(args, theme)].join("\n");
|
|
212
|
+
}
|
|
213
|
+
const GROUP_FAILURE_MAX_LENGTH = 120;
|
|
214
|
+
const GROUP_MAX_IDS = 20;
|
|
215
|
+
const GROUP_MAX_SNAPSHOT_ITEMS = 10_000;
|
|
216
|
+
const TODO_ACTIONS = new Set(["create", "create_many", "update", "list", "get", "delete", "clear"]);
|
|
217
|
+
function safeRecord(value) {
|
|
218
|
+
try {
|
|
219
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
220
|
+
? value
|
|
221
|
+
: undefined;
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return undefined;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function safeValue(record, key) {
|
|
228
|
+
try {
|
|
229
|
+
return record[key];
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function safeString(value) {
|
|
236
|
+
return typeof value === "string" ? value : undefined;
|
|
237
|
+
}
|
|
238
|
+
function groupDetails(value) {
|
|
239
|
+
const details = safeRecord(value);
|
|
240
|
+
if (!details || safeValue(details, "schemaVersion") !== TODO_DETAILS_SCHEMA_VERSION)
|
|
241
|
+
return undefined;
|
|
242
|
+
const action = safeString(safeValue(details, "action"));
|
|
243
|
+
if (!action || !TODO_ACTIONS.has(action))
|
|
244
|
+
return undefined;
|
|
245
|
+
const operation = safeRecord(safeValue(details, "operation"));
|
|
246
|
+
if (!operation || safeValue(operation, "kind") !== action)
|
|
247
|
+
return undefined;
|
|
248
|
+
return { action, operation, items: safeValue(details, "items") };
|
|
249
|
+
}
|
|
250
|
+
function groupPositiveInteger(value) {
|
|
251
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;
|
|
252
|
+
}
|
|
253
|
+
function groupIds(value) {
|
|
254
|
+
try {
|
|
255
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > GROUP_MAX_IDS)
|
|
256
|
+
return undefined;
|
|
257
|
+
const ids = [];
|
|
258
|
+
for (const valueAtIndex of value) {
|
|
259
|
+
const id = groupPositiveInteger(valueAtIndex);
|
|
260
|
+
if (id === undefined)
|
|
261
|
+
return undefined;
|
|
262
|
+
ids.push(id);
|
|
263
|
+
}
|
|
264
|
+
return ids;
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function groupNonNegativeInteger(value) {
|
|
271
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
272
|
+
}
|
|
273
|
+
function formatGroupStatusCounts(value, resultCount) {
|
|
274
|
+
const count = groupNonNegativeInteger(resultCount);
|
|
275
|
+
if (count === undefined)
|
|
276
|
+
return undefined;
|
|
277
|
+
if (count === 0)
|
|
278
|
+
return "no tasks";
|
|
279
|
+
const rawCounts = safeRecord(value);
|
|
280
|
+
if (!rawCounts)
|
|
281
|
+
return undefined;
|
|
282
|
+
const parts = [];
|
|
283
|
+
let total = 0;
|
|
284
|
+
for (const status of ["pending", "in_progress", "completed", "deleted"]) {
|
|
285
|
+
const statusCount = groupNonNegativeInteger(safeValue(rawCounts, status));
|
|
286
|
+
if (statusCount === undefined)
|
|
287
|
+
continue;
|
|
288
|
+
total += statusCount;
|
|
289
|
+
if (statusCount > 0)
|
|
290
|
+
parts.push(`${statusCount} ${status}`);
|
|
291
|
+
}
|
|
292
|
+
return total === count && parts.length ? parts.join(", ") : undefined;
|
|
293
|
+
}
|
|
294
|
+
function groupItemStatus(value, id) {
|
|
295
|
+
try {
|
|
296
|
+
if (!Array.isArray(value) || value.length > GROUP_MAX_SNAPSHOT_ITEMS)
|
|
297
|
+
return undefined;
|
|
298
|
+
for (const rawItem of value) {
|
|
299
|
+
const item = safeRecord(rawItem);
|
|
300
|
+
if (!item || safeValue(item, "id") !== id)
|
|
301
|
+
continue;
|
|
302
|
+
const status = safeString(safeValue(item, "status"));
|
|
303
|
+
return status && isTodoStatus(status) ? status : undefined;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
return undefined;
|
|
308
|
+
}
|
|
309
|
+
return undefined;
|
|
310
|
+
}
|
|
311
|
+
function formatGroupFailure(result) {
|
|
312
|
+
try {
|
|
313
|
+
for (const block of result?.content.slice(0, 8) ?? []) {
|
|
314
|
+
if (block.type !== "text" || typeof block.text !== "string")
|
|
315
|
+
continue;
|
|
316
|
+
const reason = block.text
|
|
317
|
+
.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ")
|
|
318
|
+
.replace(/\s+/g, " ")
|
|
319
|
+
.trim();
|
|
320
|
+
if (!reason)
|
|
321
|
+
continue;
|
|
322
|
+
return reason.length > GROUP_FAILURE_MAX_LENGTH ? `${reason.slice(0, GROUP_FAILURE_MAX_LENGTH - 1)}…` : reason;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
// Tool results can come from historical or third-party sources.
|
|
327
|
+
}
|
|
328
|
+
return "tool failed";
|
|
329
|
+
}
|
|
330
|
+
function formatTodoGroupSuccess(result) {
|
|
331
|
+
const details = groupDetails(result.details);
|
|
332
|
+
if (!details)
|
|
333
|
+
return undefined;
|
|
334
|
+
switch (details.action) {
|
|
335
|
+
case "create":
|
|
336
|
+
case "create_many": {
|
|
337
|
+
const ids = groupIds(safeValue(details.operation, "ids"));
|
|
338
|
+
if (!ids || (details.action === "create" && ids.length !== 1))
|
|
339
|
+
return undefined;
|
|
340
|
+
return `todo created ${ids.length} ${ids.length === 1 ? "task" : "tasks"} ${ids.map((id) => `#${id}`).join(", ")}`;
|
|
341
|
+
}
|
|
342
|
+
case "update": {
|
|
343
|
+
const id = groupPositiveInteger(safeValue(details.operation, "id"));
|
|
344
|
+
const status = safeString(safeValue(details.operation, "status"));
|
|
345
|
+
return id !== undefined && status && isTodoStatus(status) ? `todo updated #${id} ${status}` : undefined;
|
|
346
|
+
}
|
|
347
|
+
case "list": {
|
|
348
|
+
const counts = formatGroupStatusCounts(safeValue(details.operation, "statusCounts"), safeValue(details.operation, "resultCount"));
|
|
349
|
+
return counts === undefined ? undefined : `todo list: ${counts}`;
|
|
350
|
+
}
|
|
351
|
+
case "get": {
|
|
352
|
+
const id = groupPositiveInteger(safeValue(details.operation, "id"));
|
|
353
|
+
const status = id === undefined ? undefined : groupItemStatus(details.items, id);
|
|
354
|
+
return status ? `todo get #${id} ${status}` : undefined;
|
|
355
|
+
}
|
|
356
|
+
case "delete": {
|
|
357
|
+
const id = groupPositiveInteger(safeValue(details.operation, "id"));
|
|
358
|
+
return id === undefined ? undefined : `todo deleted #${id}`;
|
|
359
|
+
}
|
|
360
|
+
case "clear": {
|
|
361
|
+
const count = callNonNegativeInteger(safeValue(details.operation, "count"));
|
|
362
|
+
return count === undefined ? undefined : `todo cleared ${count} ${count === 1 ? "task" : "tasks"}`;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
/** Compact result-aware summary used only by collapsed todo tool groups. */
|
|
367
|
+
export function formatTodoGroupCall(args, theme, context) {
|
|
368
|
+
if (context.isError) {
|
|
369
|
+
return `${formatTodoCall(args, theme, false)} ${theme.fg("error", `failed: ${formatGroupFailure(context.result)}`)}`;
|
|
370
|
+
}
|
|
371
|
+
if (!context.isPartial && context.result) {
|
|
372
|
+
const summary = formatTodoGroupSuccess(context.result);
|
|
373
|
+
if (summary)
|
|
374
|
+
return theme.fg("toolTitle", summary);
|
|
375
|
+
}
|
|
376
|
+
return formatTodoCall(args, theme, false);
|
|
377
|
+
}
|
|
99
378
|
export function formatCommandList(state) {
|
|
100
379
|
const visible = visibleTodos(state);
|
|
101
380
|
if (!visible.length)
|
|
102
381
|
return "No todos yet.";
|
|
103
382
|
const lines = [];
|
|
383
|
+
let shown = 0;
|
|
104
384
|
for (const status of ["in_progress", "pending", "completed"]) {
|
|
105
385
|
const group = visible.filter((item) => item.status === status).sort(byIdAsc);
|
|
106
|
-
if (!group.length)
|
|
386
|
+
if (!group.length || shown >= LIST_DISPLAY_MAX_ITEMS)
|
|
107
387
|
continue;
|
|
108
388
|
lines.push(status);
|
|
109
389
|
for (const item of group) {
|
|
390
|
+
if (shown >= LIST_DISPLAY_MAX_ITEMS)
|
|
391
|
+
break;
|
|
110
392
|
const active = item.status === "in_progress" && item.activeForm ? ` (${item.activeForm})` : "";
|
|
111
393
|
const owner = item.owner ? ` @${item.owner}` : "";
|
|
112
394
|
const unresolved = unresolvedDependencyIds(state, item);
|
|
113
395
|
const deps = unresolved.length ? ` blocked by ${unresolved.map((id) => `#${id}`).join(",")}` : "";
|
|
114
396
|
lines.push(` ${STATUS_MARK[item.status]} #${item.id} ${item.subject}${active}${owner}${deps}`);
|
|
397
|
+
shown++;
|
|
115
398
|
}
|
|
116
399
|
}
|
|
400
|
+
if (visible.length > shown) {
|
|
401
|
+
lines.push(`… and ${visible.length - shown} more; use todo list with limit and afterId to page.`);
|
|
402
|
+
}
|
|
117
403
|
return lines.join("\n");
|
|
118
404
|
}
|
|
119
405
|
//# sourceMappingURL=view.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../../src/extensions/todo/view.ts"],"names":[],"mappings":"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","sourcesContent":["import { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { TodoItem, TodoState, TodoStatus } from \"./schema.ts\";\nimport { unresolvedDependencyIds } from \"./state.ts\";\n\nexport const STATUS_MARK: Record<TodoStatus, string> = {\n\tpending: \"[ ]\",\n\tin_progress: \"[>]\",\n\tcompleted: \"[x]\",\n\tdeleted: \"[-]\",\n};\n\nexport const STATUS_COLOR: Record<TodoStatus, \"dim\" | \"warning\" | \"success\" | \"muted\"> = {\n\tpending: \"dim\",\n\tin_progress: \"warning\",\n\tcompleted: \"success\",\n\tdeleted: \"muted\",\n};\n\nconst OVERLAY_BODY_MAX_ITEMS = 10;\n\nfunction visibleTodos(state: TodoState): TodoItem[] {\n\treturn state.items.filter((item) => item.status !== \"deleted\");\n}\n\nexport function hasVisibleOverlayItems(state: TodoState, hiddenCompleted: ReadonlySet<number>): boolean {\n\treturn visibleTodos(state).some((item) => item.status !== \"completed\" || !hiddenCompleted.has(item.id));\n}\n\nfunction todoCounts(items: TodoItem[]): { total: number; pending: number; inProgress: number; completed: number } {\n\treturn {\n\t\ttotal: items.length,\n\t\tpending: items.filter((item) => item.status === \"pending\").length,\n\t\tinProgress: items.filter((item) => item.status === \"in_progress\").length,\n\t\tcompleted: items.filter((item) => item.status === \"completed\").length,\n\t};\n}\n\nexport function renderOverlayLines(\n\tstate: TodoState,\n\ttheme: Theme,\n\twidth: number,\n\thiddenCompleted: ReadonlySet<number>,\n): string[] {\n\tconst allVisible = visibleTodos(state);\n\tconst visible = allVisible.filter((item) => item.status !== \"completed\" || !hiddenCompleted.has(item.id));\n\tif (!visible.length) return [];\n\n\tconst counts = todoCounts(allVisible);\n\tconst hasActive = visible.some((item) => item.status === \"pending\" || item.status === \"in_progress\");\n\tconst heading = `${theme.fg(hasActive ? \"accent\" : \"dim\", \"Todos\")} ${theme.fg(\"dim\", `(${counts.completed}/${counts.total})`)}`;\n\tconst lines = [truncateToWidth(heading, width, \"...\")];\n\n\tconst showIds = visible.some((item) => item.blockedBy?.length);\n\tconst body = chooseOverlayItems(visible, state, OVERLAY_BODY_MAX_ITEMS);\n\tfor (const item of body.items) {\n\t\tlines.push(truncateToWidth(` ${formatOverlayItem(item, state, theme, showIds)}`, width, \"...\"));\n\t}\n\tif (body.hidden.length > 0) {\n\t\tlines.push(truncateToWidth(theme.fg(\"dim\", ` ${formatHiddenSummary(body.hidden)}`), width, \"...\"));\n\t}\n\tlines.push(\"\");\n\treturn lines;\n}\n\nfunction byIdAsc(first: TodoItem, second: TodoItem): number {\n\treturn first.id - second.id;\n}\n\nfunction overlayPriority(state: TodoState, item: TodoItem): number {\n\tif (item.status === \"in_progress\") return 0;\n\tif (item.status === \"pending\" && unresolvedDependencyIds(state, item).length === 0) return 1;\n\tif (item.status === \"pending\") return 2;\n\treturn 3; // Completed items here are recent; older ones are hidden by TodoOverlay.\n}\n\nfunction chooseOverlayItems(\n\titems: TodoItem[],\n\tstate: TodoState,\n\tmaxBody: number,\n): { items: TodoItem[]; hidden: TodoItem[] } {\n\tconst prioritized = [...items].sort((first, second) => {\n\t\tconst priorityDelta = overlayPriority(state, first) - overlayPriority(state, second);\n\t\treturn priorityDelta || byIdAsc(first, second);\n\t});\n\tif (prioritized.length <= maxBody) return { items: prioritized, hidden: [] };\n\n\tconst shown = prioritized.slice(0, Math.max(1, maxBody - 1));\n\treturn { items: shown, hidden: prioritized.slice(shown.length) };\n}\n\nfunction formatHiddenSummary(items: TodoItem[]): string {\n\tconst counts = todoCounts(items);\n\tconst parts: string[] = [];\n\tif (counts.inProgress) parts.push(`${counts.inProgress} in progress`);\n\tif (counts.pending) parts.push(`${counts.pending} pending`);\n\tif (counts.completed) parts.push(`${counts.completed} completed`);\n\treturn `+${items.length} more${parts.length ? ` (${parts.join(\", \")})` : \"\"}`;\n}\n\nfunction formatOverlayItem(item: TodoItem, state: TodoState, theme: Theme, showId: boolean): string {\n\tlet text = theme.fg(STATUS_COLOR[item.status], STATUS_MARK[item.status]);\n\tif (showId) text += ` ${theme.fg(\"accent\", `#${item.id}`)}`;\n\tconst subject =\n\t\titem.status === \"completed\" ? theme.strikethrough(theme.fg(\"dim\", item.subject)) : theme.fg(\"text\", item.subject);\n\ttext += ` ${subject}`;\n\tif (item.status === \"in_progress\" && item.activeForm) text += ` ${theme.fg(\"dim\", `(${item.activeForm})`)}`;\n\n\tconst unresolved = unresolvedDependencyIds(state, item);\n\tif (unresolved.length) {\n\t\ttext += ` ${theme.fg(\"dim\", `blocked by ${unresolved.map((id) => `#${id}`).join(\",\")}`)}`;\n\t\tif (item.status === \"pending\" || item.status === \"in_progress\")\n\t\t\ttext += ` ${theme.fg(\"warning\", \"(deps incomplete)\")}`;\n\t}\n\treturn text;\n}\n\nexport function formatCommandList(state: TodoState): string {\n\tconst visible = visibleTodos(state);\n\tif (!visible.length) return \"No todos yet.\";\n\tconst lines: string[] = [];\n\tfor (const status of [\"in_progress\", \"pending\", \"completed\"] as const) {\n\t\tconst group = visible.filter((item) => item.status === status).sort(byIdAsc);\n\t\tif (!group.length) continue;\n\t\tlines.push(status);\n\t\tfor (const item of group) {\n\t\t\tconst active = item.status === \"in_progress\" && item.activeForm ? ` (${item.activeForm})` : \"\";\n\t\t\tconst owner = item.owner ? ` @${item.owner}` : \"\";\n\t\t\tconst unresolved = unresolvedDependencyIds(state, item);\n\t\t\tconst deps = unresolved.length ? ` blocked by ${unresolved.map((id) => `#${id}`).join(\",\")}` : \"\";\n\t\t\tlines.push(` ${STATUS_MARK[item.status]} #${item.id} ${item.subject}${active}${owner}${deps}`);\n\t\t}\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../../src/extensions/todo/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EACN,2BAA2B,GAK3B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,CAAC,MAAM,WAAW,GAA+B;IACtD,OAAO,EAAE,KAAK;IACd,WAAW,EAAE,KAAK;IAClB,SAAS,EAAE,KAAK;IAChB,OAAO,EAAE,KAAK;CACd,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAgE;IACxF,OAAO,EAAE,KAAK;IACd,WAAW,EAAE,SAAS;IACtB,SAAS,EAAE,SAAS;IACpB,OAAO,EAAE,OAAO;CAChB,CAAC;AAEF,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAElC,SAAS,YAAY,CAAC,KAAgB,EAAc;IACnD,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AAAA,CAC/D;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAgB,EAAE,eAAoC,EAAW;IACvG,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;AAAA,CACxG;AAED,SAAS,UAAU,CAAC,KAAiB,EAA6E;IACjH,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IAChF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,OAAO,EAAE,CAAC;aAC3C,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa;YAAE,MAAM,CAAC,UAAU,EAAE,CAAC;aACvD,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW;YAAE,MAAM,CAAC,SAAS,EAAE,CAAC;IAC1D,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd;AAED,MAAM,UAAU,kBAAkB,CACjC,KAAgB,EAChB,KAAY,EACZ,KAAa,EACb,eAAoC,EACzB;IACX,MAAM,UAAU,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1G,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAE/B,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC;IACrG,MAAM,OAAO,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;IACjI,MAAM,KAAK,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAEvD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC/D,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAAE,sBAAsB,CAAC,CAAC;IACxE,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAClG,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IACrG,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,KAAK,CAAC;AAAA,CACb;AAED,SAAS,OAAO,CAAC,KAAe,EAAE,MAAgB,EAAU;IAC3D,OAAO,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;AAAA,CAC5B;AAED,SAAS,eAAe,CAAC,KAAgB,EAAE,IAAc,EAAU;IAClE,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa;QAAE,OAAO,CAAC,CAAC;IAC5C,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC7F,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC;IACxC,OAAO,CAAC,CAAC,CAAC,yEAAyE;AAA1E,CACT;AAED,SAAS,kBAAkB,CAC1B,KAAiB,EACjB,KAAgB,EAChB,OAAe,EAC6B;IAC5C,MAAM,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;QACtD,MAAM,aAAa,GAAG,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACrF,OAAO,aAAa,IAAI,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAAA,CAC/C,CAAC,CAAC;IACH,IAAI,WAAW,CAAC,MAAM,IAAI,OAAO;QAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAE7E,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;AAAA,CACjE;AAED,SAAS,mBAAmB,CAAC,KAAiB,EAAU;IACvD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,MAAM,CAAC,UAAU;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,UAAU,cAAc,CAAC,CAAC;IACtE,IAAI,MAAM,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,SAAS,YAAY,CAAC,CAAC;IAClE,OAAO,IAAI,KAAK,CAAC,MAAM,QAAQ,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAAA,CAC9E;AAED,SAAS,iBAAiB,CAAC,IAAc,EAAE,KAAgB,EAAE,KAAY,EAAE,MAAe,EAAU;IACnG,IAAI,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACzE,IAAI,MAAM;QAAE,IAAI,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IAC5D,MAAM,OAAO,GACZ,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IACnH,IAAI,IAAI,IAAI,OAAO,EAAE,CAAC;IACtB,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa,IAAI,IAAI,CAAC,UAAU;QAAE,IAAI,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;IAE5G,MAAM,UAAU,GAAG,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACxD,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACvB,IAAI,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QAC1F,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,aAAa;YAC7D,IAAI,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,mBAAmB,CAAC,EAAE,CAAC;IACzD,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAUD,MAAM,WAAW,GAAG,CAAC,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,WAAW,EAAE,cAAc,CAAU,CAAC;AAE3G,SAAS,QAAQ,CAAC,KAAc,EAAU;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAAA,CACrD;AAED,SAAS,MAAM,CAAC,KAAc,EAAsB;IACnD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CAChF;AAED,SAAS,OAAO,CAAC,KAAc,EAAY;IAC1C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAAA,CACvG;AAED,SAAS,eAAe,CAAC,KAAc,EAAsB;IAC5D,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CACvD;AAED,SAAS,iBAAiB,CAAC,KAAc,EAAU;IAClD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACtC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,SAAS;QACvE,MAAM,OAAO,GAAG,QAAQ,CAAE,IAAgC,CAAC,OAAO,CAAC,CAAC;QACpE,IAAI,OAAO;YAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAAA,CAC3B;AAED,SAAS,sBAAsB,CAAC,KAAc,EAAsB;IACnE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CAC9F;AAED,SAAS,YAAY,CAAC,KAAa,EAAuB;IACzD,OAAO,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;AAAA,CACzC;AAED,SAAS,kBAAkB,CAAC,IAA8B,EAAE,KAAY,EAAU;IACjF,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAEtF,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3C,IAAI,KAAK,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC5B,IAAI,EAAE,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IAE/D,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,IAAI,MAAM,IAAI,YAAY,CAAC,MAAM,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAEvF,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,IAAI,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAEnD,6EAA6E;IAC7E,MAAM,aAAa,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACjF,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,IAAI,aAAa;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC;IAEtF,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAAA,CACvB;AAED,SAAS,iBAAiB,CAAC,IAA8B,EAAE,KAAY,EAAY;IAClF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,KAAa,EAAE,EAAE,CAAC;QAC9C,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC;IAAA,CAC7D,CAAC;IAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtC,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAChD,IAAI,CAAC,OAAO,EAAE,GAAG,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACpE,CAAC;IACF,CAAC;IAED,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;IACjD,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;IAC/C,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IACrC,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,IAAI,GAAG,CAAC,MAAM;YAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,IAAI,IAAI,EAAE,cAAc,KAAK,IAAI;QAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAClC,IAAI,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtC,IAAI,OAAO,KAAK,SAAS;QAAE,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5D,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IACrC,IAAI,IAAI,EAAE,aAAa,KAAK,IAAI;QAAE,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAChE,IAAI,IAAI,EAAE,OAAO,KAAK,IAAI;QAAE,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,sBAAsB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAClE,IAAI,aAAa,KAAK,SAAS;QAAE,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC9E,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,CAAC;IAChC,IAAI,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAChG,OAAO,KAAK,CAAC;AAAA,CACb;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAA8B,EAAE,KAAY,EAAE,QAAiB,EAAU;IACvG,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACjD,IAAI,CAAC,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/B,OAAO,CAAC,QAAQ,EAAE,GAAG,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAAA,CAChE;AAcD,MAAM,wBAAwB,GAAG,GAAG,CAAC;AACrC,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,wBAAwB,GAAG,MAAM,CAAC;AACxC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;AAEpG,SAAS,UAAU,CAAC,KAAc,EAAuC;IACxE,IAAI,CAAC;QACJ,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAC1E,CAAC,CAAE,KAAiC;YACpC,CAAC,CAAC,SAAS,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AAAA,CACD;AAED,SAAS,SAAS,CAAC,MAA+B,EAAE,GAAW,EAAW;IACzE,IAAI,CAAC;QACJ,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AAAA,CACD;AAED,SAAS,UAAU,CAAC,KAAc,EAAsB;IACvD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CACrD;AAED,SAAS,YAAY,CAAC,KAAc,EAAgC;IACnE,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO,IAAI,SAAS,CAAC,OAAO,EAAE,eAAe,CAAC,KAAK,2BAA2B;QAAE,OAAO,SAAS,CAAC;IACtG,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IACxD,IAAI,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3D,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;IAC9D,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC;IAC5E,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;AAAA,CACjE;AAED,SAAS,oBAAoB,CAAC,KAAc,EAAsB;IACjE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CAClG;AAED,SAAS,QAAQ,CAAC,KAAc,EAAwB;IACvD,IAAI,CAAC;QACJ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,aAAa;YAAE,OAAO,SAAS,CAAC;QAClG,MAAM,GAAG,GAAa,EAAE,CAAC;QACzB,KAAK,MAAM,YAAY,IAAI,KAAK,EAAE,CAAC;YAClC,MAAM,EAAE,GAAG,oBAAoB,CAAC,YAAY,CAAC,CAAC;YAC9C,IAAI,EAAE,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YACvC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACd,CAAC;QACD,OAAO,GAAG,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AAAA,CACD;AAED,SAAS,uBAAuB,CAAC,KAAc,EAAsB;IACpE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CAClG;AAED,SAAS,uBAAuB,CAAC,KAAc,EAAE,WAAoB,EAAsB;IAC1F,MAAM,KAAK,GAAG,uBAAuB,CAAC,WAAW,CAAC,CAAC;IACnD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IAEnC,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,MAAM,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,CAAU,EAAE,CAAC;QAClF,MAAM,WAAW,GAAG,uBAAuB,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1E,IAAI,WAAW,KAAK,SAAS;YAAE,SAAS;QACxC,KAAK,IAAI,WAAW,CAAC;QACrB,IAAI,WAAW,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,IAAI,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,KAAK,KAAK,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CACtE;AAED,SAAS,eAAe,CAAC,KAAc,EAAE,EAAU,EAA0B;IAC5E,IAAI,CAAC;QACJ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,wBAAwB;YAAE,OAAO,SAAS,CAAC;QACvF,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;YACjC,IAAI,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;gBAAE,SAAS;YACpD,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;YACrD,OAAO,MAAM,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5D,CAAC;IACF,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,SAAS,kBAAkB,CAAC,MAA4C,EAAU;IACjF,IAAI,CAAC;QACJ,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACvD,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;gBAAE,SAAS;YACtE,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI;iBACvB,OAAO,CAAC,+BAA+B,EAAE,GAAG,CAAC;iBAC7C,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;iBACpB,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,OAAO,MAAM,CAAC,MAAM,GAAG,wBAAwB,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,wBAAwB,GAAG,CAAC,CAAC,KAAG,CAAC,CAAC,CAAC,MAAM,CAAC;QAChH,CAAC;IACF,CAAC;IAAC,MAAM,CAAC;QACR,gEAAgE;IACjE,CAAC;IACD,OAAO,aAAa,CAAC;AAAA,CACrB;AAED,SAAS,sBAAsB,CAAC,MAAgC,EAAsB;IACrF,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAE/B,QAAQ,OAAO,CAAC,MAAM,EAAE,CAAC;QACxB,KAAK,QAAQ,CAAC;QACd,KAAK,aAAa,EAAE,CAAC;YACpB,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC;gBAAE,OAAO,SAAS,CAAC;YAChF,OAAO,gBAAgB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpH,CAAC;QACD,KAAK,QAAQ,EAAE,CAAC;YACf,MAAM,EAAE,GAAG,oBAAoB,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;YACpE,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;YAClE,OAAO,EAAE,KAAK,SAAS,IAAI,MAAM,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,iBAAiB,EAAE,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACzG,CAAC;QACD,KAAK,MAAM,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,uBAAuB,CACrC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,EAC5C,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,CAC3C,CAAC;YACF,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,MAAM,EAAE,CAAC;QAClE,CAAC;QACD,KAAK,KAAK,EAAE,CAAC;YACZ,MAAM,EAAE,GAAG,oBAAoB,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;YACpE,MAAM,MAAM,GAAG,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACjF,OAAO,MAAM,CAAC,CAAC,CAAC,aAAa,EAAE,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACzD,CAAC;QACD,KAAK,QAAQ,EAAE,CAAC;YACf,MAAM,EAAE,GAAG,oBAAoB,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;YACpE,OAAO,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC7D,CAAC;QACD,KAAK,OAAO,EAAE,CAAC;YACd,MAAM,KAAK,GAAG,sBAAsB,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;YAC5E,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,KAAK,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACpG,CAAC;IACF,CAAC;AAAA,CACD;AAED,4EAA4E;AAC5E,MAAM,UAAU,mBAAmB,CAClC,IAA8B,EAC9B,KAAY,EACZ,OAA+B,EACtB;IACT,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,OAAO,GAAG,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;IACtH,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,sBAAsB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvD,IAAI,OAAO;YAAE,OAAO,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAAA,CAC1C;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAgB,EAAU;IAC3D,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACpC,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,eAAe,CAAC;IAC5C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,MAAM,IAAI,CAAC,aAAa,EAAE,SAAS,EAAE,WAAW,CAAU,EAAE,CAAC;QACvE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7E,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,IAAI,sBAAsB;YAAE,SAAS;QAC/D,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,KAAK,IAAI,sBAAsB;gBAAE,MAAM;YAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,aAAa,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/F,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,MAAM,UAAU,GAAG,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACxD,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClG,KAAK,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,IAAI,EAAE,CAAC,CAAC;YAChG,KAAK,EAAE,CAAC;QACT,CAAC;IACF,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,WAAS,OAAO,CAAC,MAAM,GAAG,KAAK,sDAAsD,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAAA,CACxB","sourcesContent":["import { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult } from \"../../core/extensions/types.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { LIST_DISPLAY_MAX_ITEMS } from \"./constants.ts\";\nimport {\n\tTODO_DETAILS_SCHEMA_VERSION,\n\ttype TodoItem,\n\ttype TodoParams,\n\ttype TodoState,\n\ttype TodoStatus,\n} from \"./schema.ts\";\nimport { unresolvedDependencyIds } from \"./state.ts\";\n\nexport const STATUS_MARK: Record<TodoStatus, string> = {\n\tpending: \"[ ]\",\n\tin_progress: \"[>]\",\n\tcompleted: \"[x]\",\n\tdeleted: \"[-]\",\n};\n\nexport const STATUS_COLOR: Record<TodoStatus, \"dim\" | \"warning\" | \"success\" | \"muted\"> = {\n\tpending: \"dim\",\n\tin_progress: \"warning\",\n\tcompleted: \"success\",\n\tdeleted: \"muted\",\n};\n\nconst OVERLAY_BODY_MAX_ITEMS = 10;\n\nfunction visibleTodos(state: TodoState): TodoItem[] {\n\treturn state.items.filter((item) => item.status !== \"deleted\");\n}\n\nexport function hasVisibleOverlayItems(state: TodoState, hiddenCompleted: ReadonlySet<number>): boolean {\n\treturn visibleTodos(state).some((item) => item.status !== \"completed\" || !hiddenCompleted.has(item.id));\n}\n\nfunction todoCounts(items: TodoItem[]): { total: number; pending: number; inProgress: number; completed: number } {\n\tconst counts = { total: items.length, pending: 0, inProgress: 0, completed: 0 };\n\tfor (const item of items) {\n\t\tif (item.status === \"pending\") counts.pending++;\n\t\telse if (item.status === \"in_progress\") counts.inProgress++;\n\t\telse if (item.status === \"completed\") counts.completed++;\n\t}\n\treturn counts;\n}\n\nexport function renderOverlayLines(\n\tstate: TodoState,\n\ttheme: Theme,\n\twidth: number,\n\thiddenCompleted: ReadonlySet<number>,\n): string[] {\n\tconst allVisible = visibleTodos(state);\n\tconst visible = allVisible.filter((item) => item.status !== \"completed\" || !hiddenCompleted.has(item.id));\n\tif (!visible.length) return [];\n\n\tconst counts = todoCounts(allVisible);\n\tconst hasActive = visible.some((item) => item.status === \"pending\" || item.status === \"in_progress\");\n\tconst heading = `${theme.fg(hasActive ? \"accent\" : \"dim\", \"Todos\")} ${theme.fg(\"dim\", `(${counts.completed}/${counts.total})`)}`;\n\tconst lines = [truncateToWidth(heading, width, \"...\")];\n\n\tconst showIds = visible.some((item) => item.blockedBy?.length);\n\tconst body = chooseOverlayItems(visible, state, OVERLAY_BODY_MAX_ITEMS);\n\tfor (const item of body.items) {\n\t\tlines.push(truncateToWidth(` ${formatOverlayItem(item, state, theme, showIds)}`, width, \"...\"));\n\t}\n\tif (body.hidden.length > 0) {\n\t\tlines.push(truncateToWidth(theme.fg(\"dim\", ` ${formatHiddenSummary(body.hidden)}`), width, \"...\"));\n\t}\n\tlines.push(\"\");\n\treturn lines;\n}\n\nfunction byIdAsc(first: TodoItem, second: TodoItem): number {\n\treturn first.id - second.id;\n}\n\nfunction overlayPriority(state: TodoState, item: TodoItem): number {\n\tif (item.status === \"in_progress\") return 0;\n\tif (item.status === \"pending\" && unresolvedDependencyIds(state, item).length === 0) return 1;\n\tif (item.status === \"pending\") return 2;\n\treturn 3; // Completed items here are recent; older ones are hidden by TodoOverlay.\n}\n\nfunction chooseOverlayItems(\n\titems: TodoItem[],\n\tstate: TodoState,\n\tmaxBody: number,\n): { items: TodoItem[]; hidden: TodoItem[] } {\n\tconst prioritized = [...items].sort((first, second) => {\n\t\tconst priorityDelta = overlayPriority(state, first) - overlayPriority(state, second);\n\t\treturn priorityDelta || byIdAsc(first, second);\n\t});\n\tif (prioritized.length <= maxBody) return { items: prioritized, hidden: [] };\n\n\tconst shown = prioritized.slice(0, Math.max(1, maxBody - 1));\n\treturn { items: shown, hidden: prioritized.slice(shown.length) };\n}\n\nfunction formatHiddenSummary(items: TodoItem[]): string {\n\tconst counts = todoCounts(items);\n\tconst parts: string[] = [];\n\tif (counts.inProgress) parts.push(`${counts.inProgress} in progress`);\n\tif (counts.pending) parts.push(`${counts.pending} pending`);\n\tif (counts.completed) parts.push(`${counts.completed} completed`);\n\treturn `+${items.length} more${parts.length ? ` (${parts.join(\", \")})` : \"\"}`;\n}\n\nfunction formatOverlayItem(item: TodoItem, state: TodoState, theme: Theme, showId: boolean): string {\n\tlet text = theme.fg(STATUS_COLOR[item.status], STATUS_MARK[item.status]);\n\tif (showId) text += ` ${theme.fg(\"accent\", `#${item.id}`)}`;\n\tconst subject =\n\t\titem.status === \"completed\" ? theme.strikethrough(theme.fg(\"dim\", item.subject)) : theme.fg(\"text\", item.subject);\n\ttext += ` ${subject}`;\n\tif (item.status === \"in_progress\" && item.activeForm) text += ` ${theme.fg(\"dim\", `(${item.activeForm})`)}`;\n\n\tconst unresolved = unresolvedDependencyIds(state, item);\n\tif (unresolved.length) {\n\t\ttext += ` ${theme.fg(\"dim\", `blocked by ${unresolved.map((id) => `#${id}`).join(\",\")}`)}`;\n\t\tif (item.status === \"pending\" || item.status === \"in_progress\")\n\t\t\ttext += ` ${theme.fg(\"warning\", \"(deps incomplete)\")}`;\n\t}\n\treturn text;\n}\n\n// ---- tool call rendering ----------------------------------------------------\n// Collapsed todo calls join the `todo` tool group, so each row must survive as a\n// single headline with no result beneath it (ToolGroupComponent drops results and\n// appends one shared expand hint). Args come straight off the wire and can be\n// partial while the call streams, so every field is read defensively.\n\ntype TodoCallArgs = Partial<Record<keyof TodoParams, unknown>>;\n\nconst EDGE_PARAMS = [\"blockedBy\", \"addBlockedBy\", \"removeBlockedBy\", \"addBlocks\", \"removeBlocks\"] as const;\n\nfunction callText(value: unknown): string {\n\treturn typeof value === \"string\" ? value.trim() : \"\";\n}\n\nfunction callId(value: unknown): number | undefined {\n\treturn typeof value === \"number\" && Number.isInteger(value) ? value : undefined;\n}\n\nfunction callIds(value: unknown): number[] {\n\treturn Array.isArray(value) ? value.filter((entry): entry is number => typeof entry === \"number\") : [];\n}\n\nfunction callArrayLength(value: unknown): number | undefined {\n\treturn Array.isArray(value) ? value.length : undefined;\n}\n\nfunction callBatchSubjects(value: unknown): string {\n\tif (!Array.isArray(value)) return \"\";\n\tconst subjects: string[] = [];\n\tfor (const item of value.slice(0, 3)) {\n\t\tif (!item || typeof item !== \"object\" || Array.isArray(item)) continue;\n\t\tconst subject = callText((item as Record<string, unknown>).subject);\n\t\tif (subject) subjects.push(subject);\n\t}\n\treturn subjects.join(\"; \");\n}\n\nfunction callNonNegativeInteger(value: unknown): number | undefined {\n\treturn typeof value === \"number\" && Number.isInteger(value) && value >= 0 ? value : undefined;\n}\n\nfunction isTodoStatus(value: string): value is TodoStatus {\n\treturn Object.hasOwn(STATUS_MARK, value);\n}\n\nfunction formatCallHeadline(args: TodoCallArgs | undefined, theme: Theme): string {\n\tconst action = callText(args?.action);\n\tconst parts = [theme.fg(\"toolTitle\", theme.bold(action ? `todo ${action}` : \"todo\"))];\n\n\tif (action === \"create_many\") {\n\t\tconst count = callArrayLength(args?.items);\n\t\tif (count !== undefined) parts.push(theme.fg(\"dim\", `${count} tasks`));\n\t}\n\n\tconst id = callId(args?.id);\n\tif (id !== undefined) parts.push(theme.fg(\"accent\", `#${id}`));\n\n\tconst status = callText(args?.status);\n\tif (status && isTodoStatus(status)) parts.push(theme.fg(STATUS_COLOR[status], status));\n\n\tconst subject = callText(args?.subject);\n\tif (subject) parts.push(theme.fg(\"text\", subject));\n\n\t// Dependency-only updates would otherwise render as a bare `todo update #3`.\n\tconst hasEdgeChange = EDGE_PARAMS.some((key) => callIds(args?.[key]).length > 0);\n\tif (!status && !subject && hasEdgeChange) parts.push(theme.fg(\"dim\", \"dependencies\"));\n\n\treturn parts.join(\" \");\n}\n\nfunction formatCallDetails(args: TodoCallArgs | undefined, theme: Theme): string[] {\n\tconst lines: string[] = [];\n\tconst push = (label: string, value: string) => {\n\t\tif (value) lines.push(theme.fg(\"dim\", `${label}: ${value}`));\n\t};\n\n\tconst action = callText(args?.action);\n\tif (action === \"create_many\") {\n\t\tconst count = callArrayLength(args?.items);\n\t\tif (count !== undefined) {\n\t\t\tconst subjects = callBatchSubjects(args?.items);\n\t\t\tpush(\"batch\", `${count} tasks${subjects ? ` (${subjects})` : \"\"}`);\n\t\t}\n\t}\n\n\tpush(\"description\", callText(args?.description));\n\tpush(\"activeForm\", callText(args?.activeForm));\n\tpush(\"owner\", callText(args?.owner));\n\tfor (const key of EDGE_PARAMS) {\n\t\tconst ids = callIds(args?.[key]);\n\t\tif (ids.length) push(key, ids.map((id) => `#${id}`).join(\",\"));\n\t}\n\tif (args?.includeDeleted === true) push(\"includeDeleted\", \"true\");\n\tconst limit = callId(args?.limit);\n\tif (limit !== undefined) push(\"limit\", String(limit));\n\tconst afterId = callId(args?.afterId);\n\tif (afterId !== undefined) push(\"afterId\", String(afterId));\n\tpush(\"query\", callText(args?.query));\n\tif (args?.unblockedOnly === true) push(\"unblockedOnly\", \"true\");\n\tif (args?.confirm === true) push(\"confirm\", \"true\");\n\tconst expectedCount = callNonNegativeInteger(args?.expectedCount);\n\tif (expectedCount !== undefined) push(\"expectedCount\", String(expectedCount));\n\tconst metadata = args?.metadata;\n\tif (metadata && typeof metadata === \"object\") push(\"metadata\", Object.keys(metadata).join(\",\"));\n\treturn lines;\n}\n\n/**\n * One-line call summary when collapsed; the same headline plus the parameters\n * the result never echoes (description, activeForm, dependencies) when expanded.\n */\nexport function formatTodoCall(args: TodoCallArgs | undefined, theme: Theme, expanded: boolean): string {\n\tconst headline = formatCallHeadline(args, theme);\n\tif (!expanded) return headline;\n\treturn [headline, ...formatCallDetails(args, theme)].join(\"\\n\");\n}\n\ninterface TodoGroupRenderContext {\n\tisError: boolean;\n\tisPartial: boolean;\n\tresult?: AgentToolResult<unknown>;\n}\n\ninterface GroupTodoDetails {\n\taction: string;\n\toperation: Record<string, unknown>;\n\titems: unknown;\n}\n\nconst GROUP_FAILURE_MAX_LENGTH = 120;\nconst GROUP_MAX_IDS = 20;\nconst GROUP_MAX_SNAPSHOT_ITEMS = 10_000;\nconst TODO_ACTIONS = new Set([\"create\", \"create_many\", \"update\", \"list\", \"get\", \"delete\", \"clear\"]);\n\nfunction safeRecord(value: unknown): Record<string, unknown> | undefined {\n\ttry {\n\t\treturn value !== null && typeof value === \"object\" && !Array.isArray(value)\n\t\t\t? (value as Record<string, unknown>)\n\t\t\t: undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction safeValue(record: Record<string, unknown>, key: string): unknown {\n\ttry {\n\t\treturn record[key];\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction safeString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" ? value : undefined;\n}\n\nfunction groupDetails(value: unknown): GroupTodoDetails | undefined {\n\tconst details = safeRecord(value);\n\tif (!details || safeValue(details, \"schemaVersion\") !== TODO_DETAILS_SCHEMA_VERSION) return undefined;\n\tconst action = safeString(safeValue(details, \"action\"));\n\tif (!action || !TODO_ACTIONS.has(action)) return undefined;\n\tconst operation = safeRecord(safeValue(details, \"operation\"));\n\tif (!operation || safeValue(operation, \"kind\") !== action) return undefined;\n\treturn { action, operation, items: safeValue(details, \"items\") };\n}\n\nfunction groupPositiveInteger(value: unknown): number | undefined {\n\treturn typeof value === \"number\" && Number.isSafeInteger(value) && value >= 1 ? value : undefined;\n}\n\nfunction groupIds(value: unknown): number[] | undefined {\n\ttry {\n\t\tif (!Array.isArray(value) || value.length === 0 || value.length > GROUP_MAX_IDS) return undefined;\n\t\tconst ids: number[] = [];\n\t\tfor (const valueAtIndex of value) {\n\t\t\tconst id = groupPositiveInteger(valueAtIndex);\n\t\t\tif (id === undefined) return undefined;\n\t\t\tids.push(id);\n\t\t}\n\t\treturn ids;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction groupNonNegativeInteger(value: unknown): number | undefined {\n\treturn typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;\n}\n\nfunction formatGroupStatusCounts(value: unknown, resultCount: unknown): string | undefined {\n\tconst count = groupNonNegativeInteger(resultCount);\n\tif (count === undefined) return undefined;\n\tif (count === 0) return \"no tasks\";\n\n\tconst rawCounts = safeRecord(value);\n\tif (!rawCounts) return undefined;\n\tconst parts: string[] = [];\n\tlet total = 0;\n\tfor (const status of [\"pending\", \"in_progress\", \"completed\", \"deleted\"] as const) {\n\t\tconst statusCount = groupNonNegativeInteger(safeValue(rawCounts, status));\n\t\tif (statusCount === undefined) continue;\n\t\ttotal += statusCount;\n\t\tif (statusCount > 0) parts.push(`${statusCount} ${status}`);\n\t}\n\treturn total === count && parts.length ? parts.join(\", \") : undefined;\n}\n\nfunction groupItemStatus(value: unknown, id: number): TodoStatus | undefined {\n\ttry {\n\t\tif (!Array.isArray(value) || value.length > GROUP_MAX_SNAPSHOT_ITEMS) return undefined;\n\t\tfor (const rawItem of value) {\n\t\t\tconst item = safeRecord(rawItem);\n\t\t\tif (!item || safeValue(item, \"id\") !== id) continue;\n\t\t\tconst status = safeString(safeValue(item, \"status\"));\n\t\t\treturn status && isTodoStatus(status) ? status : undefined;\n\t\t}\n\t} catch {\n\t\treturn undefined;\n\t}\n\treturn undefined;\n}\n\nfunction formatGroupFailure(result: AgentToolResult<unknown> | undefined): string {\n\ttry {\n\t\tfor (const block of result?.content.slice(0, 8) ?? []) {\n\t\t\tif (block.type !== \"text\" || typeof block.text !== \"string\") continue;\n\t\t\tconst reason = block.text\n\t\t\t\t.replace(/[\\u0000-\\u001f\\u007f-\\u009f]/g, \" \")\n\t\t\t\t.replace(/\\s+/g, \" \")\n\t\t\t\t.trim();\n\t\t\tif (!reason) continue;\n\t\t\treturn reason.length > GROUP_FAILURE_MAX_LENGTH ? `${reason.slice(0, GROUP_FAILURE_MAX_LENGTH - 1)}…` : reason;\n\t\t}\n\t} catch {\n\t\t// Tool results can come from historical or third-party sources.\n\t}\n\treturn \"tool failed\";\n}\n\nfunction formatTodoGroupSuccess(result: AgentToolResult<unknown>): string | undefined {\n\tconst details = groupDetails(result.details);\n\tif (!details) return undefined;\n\n\tswitch (details.action) {\n\t\tcase \"create\":\n\t\tcase \"create_many\": {\n\t\t\tconst ids = groupIds(safeValue(details.operation, \"ids\"));\n\t\t\tif (!ids || (details.action === \"create\" && ids.length !== 1)) return undefined;\n\t\t\treturn `todo created ${ids.length} ${ids.length === 1 ? \"task\" : \"tasks\"} ${ids.map((id) => `#${id}`).join(\", \")}`;\n\t\t}\n\t\tcase \"update\": {\n\t\t\tconst id = groupPositiveInteger(safeValue(details.operation, \"id\"));\n\t\t\tconst status = safeString(safeValue(details.operation, \"status\"));\n\t\t\treturn id !== undefined && status && isTodoStatus(status) ? `todo updated #${id} ${status}` : undefined;\n\t\t}\n\t\tcase \"list\": {\n\t\t\tconst counts = formatGroupStatusCounts(\n\t\t\t\tsafeValue(details.operation, \"statusCounts\"),\n\t\t\t\tsafeValue(details.operation, \"resultCount\"),\n\t\t\t);\n\t\t\treturn counts === undefined ? undefined : `todo list: ${counts}`;\n\t\t}\n\t\tcase \"get\": {\n\t\t\tconst id = groupPositiveInteger(safeValue(details.operation, \"id\"));\n\t\t\tconst status = id === undefined ? undefined : groupItemStatus(details.items, id);\n\t\t\treturn status ? `todo get #${id} ${status}` : undefined;\n\t\t}\n\t\tcase \"delete\": {\n\t\t\tconst id = groupPositiveInteger(safeValue(details.operation, \"id\"));\n\t\t\treturn id === undefined ? undefined : `todo deleted #${id}`;\n\t\t}\n\t\tcase \"clear\": {\n\t\t\tconst count = callNonNegativeInteger(safeValue(details.operation, \"count\"));\n\t\t\treturn count === undefined ? undefined : `todo cleared ${count} ${count === 1 ? \"task\" : \"tasks\"}`;\n\t\t}\n\t}\n}\n\n/** Compact result-aware summary used only by collapsed todo tool groups. */\nexport function formatTodoGroupCall(\n\targs: TodoCallArgs | undefined,\n\ttheme: Theme,\n\tcontext: TodoGroupRenderContext,\n): string {\n\tif (context.isError) {\n\t\treturn `${formatTodoCall(args, theme, false)} ${theme.fg(\"error\", `failed: ${formatGroupFailure(context.result)}`)}`;\n\t}\n\tif (!context.isPartial && context.result) {\n\t\tconst summary = formatTodoGroupSuccess(context.result);\n\t\tif (summary) return theme.fg(\"toolTitle\", summary);\n\t}\n\treturn formatTodoCall(args, theme, false);\n}\n\nexport function formatCommandList(state: TodoState): string {\n\tconst visible = visibleTodos(state);\n\tif (!visible.length) return \"No todos yet.\";\n\tconst lines: string[] = [];\n\tlet shown = 0;\n\tfor (const status of [\"in_progress\", \"pending\", \"completed\"] as const) {\n\t\tconst group = visible.filter((item) => item.status === status).sort(byIdAsc);\n\t\tif (!group.length || shown >= LIST_DISPLAY_MAX_ITEMS) continue;\n\t\tlines.push(status);\n\t\tfor (const item of group) {\n\t\t\tif (shown >= LIST_DISPLAY_MAX_ITEMS) break;\n\t\t\tconst active = item.status === \"in_progress\" && item.activeForm ? ` (${item.activeForm})` : \"\";\n\t\t\tconst owner = item.owner ? ` @${item.owner}` : \"\";\n\t\t\tconst unresolved = unresolvedDependencyIds(state, item);\n\t\t\tconst deps = unresolved.length ? ` blocked by ${unresolved.map((id) => `#${id}`).join(\",\")}` : \"\";\n\t\t\tlines.push(` ${STATUS_MARK[item.status]} #${item.id} ${item.subject}${active}${owner}${deps}`);\n\t\t\tshown++;\n\t\t}\n\t}\n\tif (visible.length > shown) {\n\t\tlines.push(`… and ${visible.length - shown} more; use todo list with limit and afterId to page.`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n"]}
|
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
* Displays a list of string options with keyboard navigation.
|
|
4
4
|
*/
|
|
5
5
|
import { Container, type TUI } from "@earendil-works/pi-tui";
|
|
6
|
+
import type { SelectOption } from "../../../core/extensions/types.ts";
|
|
6
7
|
export interface ExtensionSelectorOptions {
|
|
7
8
|
tui?: TUI;
|
|
8
9
|
timeout?: number;
|
|
9
10
|
onToggleToolsExpanded?: () => void;
|
|
11
|
+
/** Muted line under the title, for context that is not itself a choice. */
|
|
12
|
+
subtitle?: string;
|
|
13
|
+
/** Overrides the "cancel" wording in the key hints (e.g. when Esc means "keep planning"). */
|
|
14
|
+
cancelHint?: string;
|
|
10
15
|
}
|
|
11
16
|
export declare class ExtensionSelectorComponent extends Container {
|
|
12
17
|
private options;
|
|
@@ -18,7 +23,7 @@ export declare class ExtensionSelectorComponent extends Container {
|
|
|
18
23
|
private baseTitle;
|
|
19
24
|
private countdown;
|
|
20
25
|
private onToggleToolsExpanded;
|
|
21
|
-
constructor(title: string, options: string
|
|
26
|
+
constructor(title: string, options: ReadonlyArray<string | SelectOption>, onSelect: (option: string) => void, onCancel: () => void, opts?: ExtensionSelectorOptions);
|
|
22
27
|
private updateList;
|
|
23
28
|
handleInput(keyData: string): void;
|
|
24
29
|
dispose(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-selector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAgC,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"extension-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-selector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAgC,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AAC3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAMtE,MAAM,WAAW,wBAAwB;IACxC,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6FAA6F;IAC7F,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAOD,qBAAa,0BAA2B,SAAQ,SAAS;IACxD,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,aAAa,CAAY;IACjC,OAAO,CAAC,gBAAgB,CAA2B;IACnD,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,qBAAqB,CAA2B;IAExD,YACC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,CAAC,MAAM,GAAG,YAAY,CAAC,EAC7C,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,EAClC,QAAQ,EAAE,MAAM,IAAI,EACpB,IAAI,CAAC,EAAE,wBAAwB,EA6C/B;IAED,OAAO,CAAC,UAAU;IAYlB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAgBjC;IAED,OAAO,IAAI,IAAI,CAEd;CACD","sourcesContent":["/**\n * Generic selector component for extensions.\n * Displays a list of string options with keyboard navigation.\n */\n\nimport { Container, getKeybindings, Spacer, Text, type TUI } from \"@earendil-works/pi-tui\";\nimport type { SelectOption } from \"../../../core/extensions/types.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { CountdownTimer } from \"./countdown-timer.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\nexport interface ExtensionSelectorOptions {\n\ttui?: TUI;\n\ttimeout?: number;\n\tonToggleToolsExpanded?: () => void;\n\t/** Muted line under the title, for context that is not itself a choice. */\n\tsubtitle?: string;\n\t/** Overrides the \"cancel\" wording in the key hints (e.g. when Esc means \"keep planning\"). */\n\tcancelHint?: string;\n}\n\n/** Normalize the string shorthand so rendering only deals with one shape. */\nfunction toSelectOption(option: string | SelectOption): SelectOption {\n\treturn typeof option === \"string\" ? { label: option } : option;\n}\n\nexport class ExtensionSelectorComponent extends Container {\n\tprivate options: SelectOption[];\n\tprivate selectedIndex = 0;\n\tprivate listContainer: Container;\n\tprivate onSelectCallback: (option: string) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate titleText: Text;\n\tprivate baseTitle: string;\n\tprivate countdown: CountdownTimer | undefined;\n\tprivate onToggleToolsExpanded: (() => void) | undefined;\n\n\tconstructor(\n\t\ttitle: string,\n\t\toptions: ReadonlyArray<string | SelectOption>,\n\t\tonSelect: (option: string) => void,\n\t\tonCancel: () => void,\n\t\topts?: ExtensionSelectorOptions,\n\t) {\n\t\tsuper();\n\n\t\tthis.options = options.map(toSelectOption);\n\t\tthis.onSelectCallback = onSelect;\n\t\tthis.onCancelCallback = onCancel;\n\t\tthis.onToggleToolsExpanded = opts?.onToggleToolsExpanded;\n\t\tthis.baseTitle = title;\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0);\n\t\tthis.addChild(this.titleText);\n\t\tif (opts?.subtitle) this.addChild(new Text(theme.fg(\"muted\", opts.subtitle), 1, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (opts?.timeout && opts.timeout > 0 && opts.tui) {\n\t\t\tthis.countdown = new CountdownTimer(\n\t\t\t\topts.timeout,\n\t\t\t\topts.tui,\n\t\t\t\t(s) => this.titleText.setText(theme.fg(\"accent\", theme.bold(`${this.baseTitle} (${s}s)`))),\n\t\t\t\t() => this.onCancelCallback(),\n\t\t\t);\n\t\t}\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\trawKeyHint(\"↑↓\", \"navigate\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.confirm\", \"select\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.cancel\", opts?.cancelHint ?? \"cancel\"),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.updateList();\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\t\tfor (let i = 0; i < this.options.length; i++) {\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst { label, description } = this.options[i];\n\t\t\tconst text = isSelected ? theme.fg(\"accent\", `→ ${label}`) : ` ${theme.fg(\"text\", label)}`;\n\t\t\tthis.listContainer.addChild(new Text(text, 1, 0));\n\t\t\t// Aligned under the label, muted so the action stays the thing you scan.\n\t\t\tif (description) this.listContainer.addChild(new Text(` ${theme.fg(\"muted\", description)}`, 1, 0));\n\t\t}\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"app.tools.expand\")) {\n\t\t\tthis.onToggleToolsExpanded?.();\n\t\t} else if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.selectedIndex = Math.max(0, this.selectedIndex - 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.selectedIndex = Math.min(this.options.length - 1, this.selectedIndex + 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n\t\t\tconst selected = this.options[this.selectedIndex];\n\t\t\tif (selected) this.onSelectCallback(selected.label);\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancelCallback();\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.countdown?.dispose();\n\t}\n}\n"]}
|
|
@@ -7,6 +7,10 @@ import { theme } from "../theme/theme.js";
|
|
|
7
7
|
import { CountdownTimer } from "./countdown-timer.js";
|
|
8
8
|
import { DynamicBorder } from "./dynamic-border.js";
|
|
9
9
|
import { keyHint, rawKeyHint } from "./keybinding-hints.js";
|
|
10
|
+
/** Normalize the string shorthand so rendering only deals with one shape. */
|
|
11
|
+
function toSelectOption(option) {
|
|
12
|
+
return typeof option === "string" ? { label: option } : option;
|
|
13
|
+
}
|
|
10
14
|
export class ExtensionSelectorComponent extends Container {
|
|
11
15
|
options;
|
|
12
16
|
selectedIndex = 0;
|
|
@@ -19,7 +23,7 @@ export class ExtensionSelectorComponent extends Container {
|
|
|
19
23
|
onToggleToolsExpanded;
|
|
20
24
|
constructor(title, options, onSelect, onCancel, opts) {
|
|
21
25
|
super();
|
|
22
|
-
this.options = options;
|
|
26
|
+
this.options = options.map(toSelectOption);
|
|
23
27
|
this.onSelectCallback = onSelect;
|
|
24
28
|
this.onCancelCallback = onCancel;
|
|
25
29
|
this.onToggleToolsExpanded = opts?.onToggleToolsExpanded;
|
|
@@ -28,6 +32,8 @@ export class ExtensionSelectorComponent extends Container {
|
|
|
28
32
|
this.addChild(new Spacer(1));
|
|
29
33
|
this.titleText = new Text(theme.fg("accent", theme.bold(title)), 1, 0);
|
|
30
34
|
this.addChild(this.titleText);
|
|
35
|
+
if (opts?.subtitle)
|
|
36
|
+
this.addChild(new Text(theme.fg("muted", opts.subtitle), 1, 0));
|
|
31
37
|
this.addChild(new Spacer(1));
|
|
32
38
|
if (opts?.timeout && opts.timeout > 0 && opts.tui) {
|
|
33
39
|
this.countdown = new CountdownTimer(opts.timeout, opts.tui, (s) => this.titleText.setText(theme.fg("accent", theme.bold(`${this.baseTitle} (${s}s)`))), () => this.onCancelCallback());
|
|
@@ -39,7 +45,7 @@ export class ExtensionSelectorComponent extends Container {
|
|
|
39
45
|
" " +
|
|
40
46
|
keyHint("tui.select.confirm", "select") +
|
|
41
47
|
" " +
|
|
42
|
-
keyHint("tui.select.cancel", "cancel"), 1, 0));
|
|
48
|
+
keyHint("tui.select.cancel", opts?.cancelHint ?? "cancel"), 1, 0));
|
|
43
49
|
this.addChild(new Spacer(1));
|
|
44
50
|
this.addChild(new DynamicBorder());
|
|
45
51
|
this.updateList();
|
|
@@ -48,10 +54,12 @@ export class ExtensionSelectorComponent extends Container {
|
|
|
48
54
|
this.listContainer.clear();
|
|
49
55
|
for (let i = 0; i < this.options.length; i++) {
|
|
50
56
|
const isSelected = i === this.selectedIndex;
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
: ` ${theme.fg("text", this.options[i])}`;
|
|
57
|
+
const { label, description } = this.options[i];
|
|
58
|
+
const text = isSelected ? theme.fg("accent", `→ ${label}`) : ` ${theme.fg("text", label)}`;
|
|
54
59
|
this.listContainer.addChild(new Text(text, 1, 0));
|
|
60
|
+
// Aligned under the label, muted so the action stays the thing you scan.
|
|
61
|
+
if (description)
|
|
62
|
+
this.listContainer.addChild(new Text(` ${theme.fg("muted", description)}`, 1, 0));
|
|
55
63
|
}
|
|
56
64
|
}
|
|
57
65
|
handleInput(keyData) {
|
|
@@ -70,7 +78,7 @@ export class ExtensionSelectorComponent extends Container {
|
|
|
70
78
|
else if (kb.matches(keyData, "tui.select.confirm") || keyData === "\n") {
|
|
71
79
|
const selected = this.options[this.selectedIndex];
|
|
72
80
|
if (selected)
|
|
73
|
-
this.onSelectCallback(selected);
|
|
81
|
+
this.onSelectCallback(selected.label);
|
|
74
82
|
}
|
|
75
83
|
else if (kb.matches(keyData, "tui.select.cancel")) {
|
|
76
84
|
this.onCancelCallback();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-selector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAY,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"extension-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/extension-selector.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Generic selector component for extensions.\n * Displays a list of string options with keyboard navigation.\n */\n\nimport { Container, getKeybindings, Spacer, Text, type TUI } from \"@earendil-works/pi-tui\";\nimport type { SelectOption } from \"../../../core/extensions/types.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { CountdownTimer } from \"./countdown-timer.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\nexport interface ExtensionSelectorOptions {\n\ttui?: TUI;\n\ttimeout?: number;\n\tonToggleToolsExpanded?: () => void;\n\t/** Muted line under the title, for context that is not itself a choice. */\n\tsubtitle?: string;\n\t/** Overrides the \"cancel\" wording in the key hints (e.g. when Esc means \"keep planning\"). */\n\tcancelHint?: string;\n}\n\n/** Normalize the string shorthand so rendering only deals with one shape. */\nfunction toSelectOption(option: string | SelectOption): SelectOption {\n\treturn typeof option === \"string\" ? { label: option } : option;\n}\n\nexport class ExtensionSelectorComponent extends Container {\n\tprivate options: SelectOption[];\n\tprivate selectedIndex = 0;\n\tprivate listContainer: Container;\n\tprivate onSelectCallback: (option: string) => void;\n\tprivate onCancelCallback: () => void;\n\tprivate titleText: Text;\n\tprivate baseTitle: string;\n\tprivate countdown: CountdownTimer | undefined;\n\tprivate onToggleToolsExpanded: (() => void) | undefined;\n\n\tconstructor(\n\t\ttitle: string,\n\t\toptions: ReadonlyArray<string | SelectOption>,\n\t\tonSelect: (option: string) => void,\n\t\tonCancel: () => void,\n\t\topts?: ExtensionSelectorOptions,\n\t) {\n\t\tsuper();\n\n\t\tthis.options = options.map(toSelectOption);\n\t\tthis.onSelectCallback = onSelect;\n\t\tthis.onCancelCallback = onCancel;\n\t\tthis.onToggleToolsExpanded = opts?.onToggleToolsExpanded;\n\t\tthis.baseTitle = title;\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(title)), 1, 0);\n\t\tthis.addChild(this.titleText);\n\t\tif (opts?.subtitle) this.addChild(new Text(theme.fg(\"muted\", opts.subtitle), 1, 0));\n\t\tthis.addChild(new Spacer(1));\n\n\t\tif (opts?.timeout && opts.timeout > 0 && opts.tui) {\n\t\t\tthis.countdown = new CountdownTimer(\n\t\t\t\topts.timeout,\n\t\t\t\topts.tui,\n\t\t\t\t(s) => this.titleText.setText(theme.fg(\"accent\", theme.bold(`${this.baseTitle} (${s}s)`))),\n\t\t\t\t() => this.onCancelCallback(),\n\t\t\t);\n\t\t}\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\trawKeyHint(\"↑↓\", \"navigate\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.confirm\", \"select\") +\n\t\t\t\t\t\" \" +\n\t\t\t\t\tkeyHint(\"tui.select.cancel\", opts?.cancelHint ?? \"cancel\"),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.updateList();\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\t\tfor (let i = 0; i < this.options.length; i++) {\n\t\t\tconst isSelected = i === this.selectedIndex;\n\t\t\tconst { label, description } = this.options[i];\n\t\t\tconst text = isSelected ? theme.fg(\"accent\", `→ ${label}`) : ` ${theme.fg(\"text\", label)}`;\n\t\t\tthis.listContainer.addChild(new Text(text, 1, 0));\n\t\t\t// Aligned under the label, muted so the action stays the thing you scan.\n\t\t\tif (description) this.listContainer.addChild(new Text(` ${theme.fg(\"muted\", description)}`, 1, 0));\n\t\t}\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"app.tools.expand\")) {\n\t\t\tthis.onToggleToolsExpanded?.();\n\t\t} else if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.selectedIndex = Math.max(0, this.selectedIndex - 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.selectedIndex = Math.min(this.options.length - 1, this.selectedIndex + 1);\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\") || keyData === \"\\n\") {\n\t\t\tconst selected = this.options[this.selectedIndex];\n\t\t\tif (selected) this.onSelectCallback(selected.label);\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancelCallback();\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.countdown?.dispose();\n\t}\n}\n"]}
|