@astralyn/pi 0.84.3 → 0.84.4

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.
Files changed (92) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cli/project-trust.d.ts.map +1 -1
  3. package/dist/cli/project-trust.js +1 -4
  4. package/dist/cli/project-trust.js.map +1 -1
  5. package/dist/core/extensions/index.d.ts +1 -1
  6. package/dist/core/extensions/index.d.ts.map +1 -1
  7. package/dist/core/extensions/index.js.map +1 -1
  8. package/dist/core/extensions/types.d.ts +2 -13
  9. package/dist/core/extensions/types.d.ts.map +1 -1
  10. package/dist/core/extensions/types.js.map +1 -1
  11. package/dist/extensions/subagent/agents-command.d.ts +4 -0
  12. package/dist/extensions/subagent/agents-command.d.ts.map +1 -0
  13. package/dist/extensions/subagent/agents-command.js +230 -0
  14. package/dist/extensions/subagent/agents-command.js.map +1 -0
  15. package/dist/extensions/subagent/agents.d.ts.map +1 -1
  16. package/dist/extensions/subagent/agents.js +2 -0
  17. package/dist/extensions/subagent/agents.js.map +1 -1
  18. package/dist/extensions/subagent/display-name.d.ts +6 -0
  19. package/dist/extensions/subagent/display-name.d.ts.map +1 -0
  20. package/dist/extensions/subagent/display-name.js +13 -0
  21. package/dist/extensions/subagent/display-name.js.map +1 -0
  22. package/dist/extensions/subagent/index.d.ts.map +1 -1
  23. package/dist/extensions/subagent/index.js +2 -127
  24. package/dist/extensions/subagent/index.js.map +1 -1
  25. package/dist/extensions/subagent/render.d.ts.map +1 -1
  26. package/dist/extensions/subagent/render.js +1 -10
  27. package/dist/extensions/subagent/render.js.map +1 -1
  28. package/dist/extensions/subagent/settings.d.ts +0 -1
  29. package/dist/extensions/subagent/settings.d.ts.map +1 -1
  30. package/dist/extensions/subagent/settings.js +3 -7
  31. package/dist/extensions/subagent/settings.js.map +1 -1
  32. package/dist/extensions/subagent/types.d.ts +2 -0
  33. package/dist/extensions/subagent/types.d.ts.map +1 -1
  34. package/dist/extensions/subagent/types.js.map +1 -1
  35. package/dist/extensions/subagent/ui/model-list.d.ts +67 -0
  36. package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -0
  37. package/dist/extensions/subagent/ui/model-list.js +242 -0
  38. package/dist/extensions/subagent/ui/model-list.js.map +1 -0
  39. package/dist/extensions/subagent/ui/profile-editor.d.ts +54 -0
  40. package/dist/extensions/subagent/ui/profile-editor.d.ts.map +1 -0
  41. package/dist/extensions/subagent/ui/profile-editor.js +154 -0
  42. package/dist/extensions/subagent/ui/profile-editor.js.map +1 -0
  43. package/dist/extensions/subagent/ui/profile-picker.d.ts +32 -0
  44. package/dist/extensions/subagent/ui/profile-picker.d.ts.map +1 -0
  45. package/dist/extensions/subagent/ui/profile-picker.js +149 -0
  46. package/dist/extensions/subagent/ui/profile-picker.js.map +1 -0
  47. package/dist/extensions/todo/constants.d.ts +6 -17
  48. package/dist/extensions/todo/constants.d.ts.map +1 -1
  49. package/dist/extensions/todo/constants.js +20 -31
  50. package/dist/extensions/todo/constants.js.map +1 -1
  51. package/dist/extensions/todo/index.d.ts.map +1 -1
  52. package/dist/extensions/todo/index.js +36 -57
  53. package/dist/extensions/todo/index.js.map +1 -1
  54. package/dist/extensions/todo/schema.d.ts +20 -59
  55. package/dist/extensions/todo/schema.d.ts.map +1 -1
  56. package/dist/extensions/todo/schema.js +23 -69
  57. package/dist/extensions/todo/schema.js.map +1 -1
  58. package/dist/extensions/todo/state.d.ts +23 -65
  59. package/dist/extensions/todo/state.d.ts.map +1 -1
  60. package/dist/extensions/todo/state.js +238 -1262
  61. package/dist/extensions/todo/state.js.map +1 -1
  62. package/dist/extensions/todo/view.d.ts +19 -10
  63. package/dist/extensions/todo/view.d.ts.map +1 -1
  64. package/dist/extensions/todo/view.js +411 -463
  65. package/dist/extensions/todo/view.js.map +1 -1
  66. package/dist/extensions/todo/widget.d.ts +15 -0
  67. package/dist/extensions/todo/widget.d.ts.map +1 -0
  68. package/dist/extensions/todo/widget.js +50 -0
  69. package/dist/extensions/todo/widget.js.map +1 -0
  70. package/dist/modes/interactive/components/extension-selector.d.ts +1 -2
  71. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  72. package/dist/modes/interactive/components/extension-selector.js +5 -11
  73. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  74. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  75. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  76. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  77. package/dist/modes/rpc/rpc-mode.js +1 -8
  78. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  79. package/docs/bundled/README.md +1 -1
  80. package/docs/bundled/extensions/subagent.md +19 -4
  81. package/docs/bundled/extensions/todo.md +84 -24
  82. package/docs/bundled/tool-presentation.md +1 -1
  83. package/npm-shrinkwrap.json +2 -2
  84. package/package.json +1 -1
  85. package/dist/extensions/subagent/picker.d.ts +0 -31
  86. package/dist/extensions/subagent/picker.d.ts.map +0 -1
  87. package/dist/extensions/subagent/picker.js +0 -109
  88. package/dist/extensions/subagent/picker.js.map +0 -1
  89. package/dist/extensions/todo/overlay.d.ts +0 -24
  90. package/dist/extensions/todo/overlay.d.ts.map +0 -1
  91. package/dist/extensions/todo/overlay.js +0 -135
  92. package/dist/extensions/todo/overlay.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"picker.js","sourceRoot":"","sources":["../../../src/extensions/subagent/picker.ts"],"names":[],"mappings":"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","sourcesContent":["import { Container, type Focusable, fuzzyFilter, getKeybindings, Input, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport { DynamicBorder } from \"../../modes/interactive/components/dynamic-border.ts\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\n\nexport interface PickerItem<T> {\n\tvalue: T;\n\tlabel: string;\n\tdetail?: string;\n\tcurrent?: boolean;\n}\n\nconst MAX_VISIBLE = 10;\n\n/**\n * Searchable selector matching the native /model experience: type to\n * fuzzy-filter, arrows wrap around the list, enter confirms, escape\n * cancels (resolves undefined). Mounted via ctx.ui.custom().\n */\nexport class SearchPickerComponent<T> extends Container implements Focusable {\n\tprivate readonly theme: Theme;\n\tprivate readonly items: PickerItem<T>[];\n\tprivate readonly onDone: (value: T | undefined) => void;\n\tprivate readonly searchInput: Input;\n\tprivate readonly listContainer: Container;\n\tprivate filtered: PickerItem<T>[];\n\tprivate selectedIndex = 0;\n\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tconstructor(theme: Theme, title: string, items: PickerItem<T>[], onDone: (value: T | undefined) => void) {\n\t\tsuper();\n\t\tthis.theme = theme;\n\t\tthis.items = items;\n\t\tthis.onDone = onDone;\n\t\tthis.filtered = items;\n\t\tconst currentIndex = items.findIndex((item) => item.current);\n\t\tif (currentIndex >= 0) this.selectedIndex = currentIndex;\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"toolTitle\", theme.bold(title)), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.searchInput = new Input();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\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\t`${theme.fg(\"muted\", \"↑↓\")} ${theme.fg(\"dim\", \"navigate\")} ${keyHint(\"tui.select.confirm\", \"select\")} ${keyHint(\"tui.select.cancel\", \"cancel\")}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.updateList();\n\t}\n\n\tprivate filter(query: string): void {\n\t\tthis.filtered = query\n\t\t\t? fuzzyFilter(this.items, query, (item) => `${item.label} ${item.detail ?? \"\"}`)\n\t\t\t: this.items;\n\t\tthis.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filtered.length - 1));\n\t\tthis.updateList();\n\t}\n\n\tprivate confirm(): void {\n\t\tconst selected = this.filtered[this.selectedIndex];\n\t\tif (selected) this.onDone(selected.value);\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(MAX_VISIBLE / 2), this.filtered.length - MAX_VISIBLE),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + MAX_VISIBLE, this.filtered.length);\n\t\tfor (let index = startIndex; index < endIndex; index++) {\n\t\t\tconst item = this.filtered[index];\n\t\t\tif (!item) continue;\n\t\t\tconst isSelected = index === this.selectedIndex;\n\t\t\tconst marker = item.current ? this.theme.fg(\"success\", \" ✓\") : \"\";\n\t\t\tconst line = isSelected\n\t\t\t\t? `${this.theme.fg(\"accent\", \"→ \")}${this.theme.fg(\"accent\", item.label)}${marker}`\n\t\t\t\t: ` ${item.label}${marker}`;\n\t\t\tthis.listContainer.addChild(new Text(line, 0, 0));\n\t\t}\n\t\tif (startIndex > 0 || endIndex < this.filtered.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(this.theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.filtered.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\t\tif (this.filtered.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(this.theme.fg(\"muted\", \" No matches\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\t\tconst detail = this.filtered[this.selectedIndex]?.detail;\n\t\tif (detail) {\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(this.theme.fg(\"muted\", ` ${detail}`), 0, 0));\n\t\t}\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.filtered.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.filtered.length - 1 : this.selectedIndex - 1;\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.filtered.length === 0) return;\n\t\t\tthis.selectedIndex = this.selectedIndex === this.filtered.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t\tthis.updateList();\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.confirm();\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onDone(undefined);\n\t\t} else {\n\t\t\tthis.searchInput.handleInput(keyData);\n\t\t\tthis.filter(this.searchInput.getValue());\n\t\t}\n\t}\n}\n"]}
@@ -1,24 +0,0 @@
1
- import type { ExtensionUIContext } from "../../core/extensions/types.ts";
2
- export declare class TodoOverlay {
3
- private ui;
4
- private tui;
5
- private registered;
6
- private knownStatuses;
7
- private completedAt;
8
- private hiddenCompleted;
9
- private completionHideTimer;
10
- /** Pure render cache: same width + visibility state → skip rebuild. */
11
- private cachedWidth;
12
- private cachedLines;
13
- setUI(ui: ExtensionUIContext): void;
14
- resetVisibility(): void;
15
- update(): void;
16
- /** Track new completions for a short confirmation window; hide historical ones. */
17
- private syncVisibilityFromState;
18
- private scheduleCompletionHide;
19
- private clearCompletionHideTimer;
20
- private invalidateRenderCache;
21
- private render;
22
- dispose(): void;
23
- }
24
- //# sourceMappingURL=overlay.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../../../src/extensions/todo/overlay.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAUzE,qBAAa,WAAW;IACvB,OAAO,CAAC,EAAE,CAAiC;IAC3C,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,mBAAmB,CAA4C;IACvE,uEAAuE;IACvE,OAAO,CAAC,WAAW,CAAqB;IACxC,OAAO,CAAC,WAAW,CAAuB;IAE1C,KAAK,CAAC,EAAE,EAAE,kBAAkB,GAAG,IAAI;IAMnC,eAAe,IAAI,IAAI;IAQvB,MAAM,IAAI,IAAI;IAoCd,mFAAmF;IACnF,OAAO,CAAC,uBAAuB;IAyC/B,OAAO,CAAC,sBAAsB;IAiB9B,OAAO,CAAC,wBAAwB;IAMhC,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,MAAM;IAUd,OAAO,IAAI,IAAI;CAOf"}
@@ -1,135 +0,0 @@
1
- import { getTodoState } from "./state.js";
2
- import { hasVisibleOverlayItems, renderOverlayLines } from "./view.js";
3
- const WIDGET_KEY = "todos";
4
- const RECENT_COMPLETION_MS = 30_000;
5
- export class TodoOverlay {
6
- constructor() {
7
- this.registered = false;
8
- this.knownStatuses = new Map();
9
- this.completedAt = new Map();
10
- this.hiddenCompleted = new Set();
11
- }
12
- setUI(ui) {
13
- if (this.ui === ui)
14
- return;
15
- this.dispose();
16
- this.ui = ui;
17
- }
18
- resetVisibility() {
19
- this.clearCompletionHideTimer();
20
- this.knownStatuses.clear();
21
- this.completedAt.clear();
22
- this.hiddenCompleted.clear();
23
- this.invalidateRenderCache();
24
- }
25
- update() {
26
- if (!this.ui)
27
- return;
28
- const state = getTodoState();
29
- this.syncVisibilityFromState(state);
30
- this.invalidateRenderCache();
31
- // Register/unregister based on state, never as a render side effect.
32
- if (!hasVisibleOverlayItems(state, this.hiddenCompleted)) {
33
- if (this.registered)
34
- this.ui.setWidget(WIDGET_KEY, undefined);
35
- this.registered = false;
36
- this.tui = undefined;
37
- return;
38
- }
39
- if (!this.registered) {
40
- this.ui.setWidget(WIDGET_KEY, (tui, theme) => {
41
- this.tui = tui;
42
- return {
43
- render: (width) => this.render(theme, width),
44
- invalidate: () => {
45
- this.registered = false;
46
- this.tui = undefined;
47
- this.invalidateRenderCache();
48
- },
49
- };
50
- }, { placement: "aboveEditor" });
51
- this.registered = true;
52
- return;
53
- }
54
- this.tui?.requestRender();
55
- }
56
- /** Track new completions for a short confirmation window; hide historical ones. */
57
- syncVisibilityFromState(state) {
58
- const now = Date.now();
59
- const nextStatuses = new Map();
60
- for (const item of state.items) {
61
- nextStatuses.set(item.id, item.status);
62
- const previousStatus = this.knownStatuses.get(item.id);
63
- if (item.status !== "completed") {
64
- this.completedAt.delete(item.id);
65
- this.hiddenCompleted.delete(item.id);
66
- continue;
67
- }
68
- if (previousStatus === undefined) {
69
- // A replayed/reloaded completion is old from this overlay's point of
70
- // view. Keep the live surface focused on current work.
71
- this.hiddenCompleted.add(item.id);
72
- this.completedAt.delete(item.id);
73
- continue;
74
- }
75
- if (previousStatus !== "completed") {
76
- this.completedAt.set(item.id, now);
77
- this.hiddenCompleted.delete(item.id);
78
- }
79
- }
80
- for (const id of this.knownStatuses.keys()) {
81
- if (nextStatuses.has(id))
82
- continue;
83
- this.completedAt.delete(id);
84
- this.hiddenCompleted.delete(id);
85
- }
86
- this.knownStatuses = nextStatuses;
87
- for (const [id, completedAt] of this.completedAt) {
88
- if (now - completedAt < RECENT_COMPLETION_MS)
89
- continue;
90
- this.completedAt.delete(id);
91
- this.hiddenCompleted.add(id);
92
- }
93
- this.scheduleCompletionHide();
94
- }
95
- scheduleCompletionHide() {
96
- this.clearCompletionHideTimer();
97
- let earliestExpiry = Infinity;
98
- for (const completedAt of this.completedAt.values()) {
99
- earliestExpiry = Math.min(earliestExpiry, completedAt + RECENT_COMPLETION_MS);
100
- }
101
- if (!Number.isFinite(earliestExpiry))
102
- return;
103
- this.completionHideTimer = setTimeout(() => {
104
- this.completionHideTimer = undefined;
105
- this.update();
106
- }, Math.max(10, earliestExpiry - Date.now()));
107
- }
108
- clearCompletionHideTimer() {
109
- if (this.completionHideTimer === undefined)
110
- return;
111
- clearTimeout(this.completionHideTimer);
112
- this.completionHideTimer = undefined;
113
- }
114
- invalidateRenderCache() {
115
- this.cachedWidth = undefined;
116
- this.cachedLines = undefined;
117
- }
118
- render(theme, width) {
119
- const normalizedWidth = Math.max(1, width);
120
- if (this.cachedLines !== undefined && this.cachedWidth === normalizedWidth)
121
- return this.cachedLines;
122
- const lines = renderOverlayLines(getTodoState(), theme, normalizedWidth, this.hiddenCompleted);
123
- this.cachedWidth = normalizedWidth;
124
- this.cachedLines = lines;
125
- return lines;
126
- }
127
- dispose() {
128
- this.ui?.setWidget(WIDGET_KEY, undefined);
129
- this.tui = undefined;
130
- this.registered = false;
131
- this.ui = undefined;
132
- this.resetVisibility();
133
- }
134
- }
135
- //# sourceMappingURL=overlay.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../../src/extensions/todo/overlay.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TUI } from \"@earendil-works/pi-tui\";\nimport type { ExtensionUIContext } from \"../../core/extensions/types.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\n\nimport type { TodoState, TodoStatus } from \"./schema.ts\";\nimport { getTodoState } from \"./state.ts\";\nimport { hasVisibleOverlayItems, renderOverlayLines } from \"./view.ts\";\n\nconst WIDGET_KEY = \"todos\";\nconst RECENT_COMPLETION_MS = 30_000;\n\nexport class TodoOverlay {\n\tprivate ui: ExtensionUIContext | undefined;\n\tprivate tui: TUI | undefined;\n\tprivate registered = false;\n\tprivate knownStatuses = new Map<number, TodoStatus>();\n\tprivate completedAt = new Map<number, number>();\n\tprivate hiddenCompleted = new Set<number>();\n\tprivate completionHideTimer: ReturnType<typeof setTimeout> | undefined;\n\t/** Pure render cache: same width + visibility state → skip rebuild. */\n\tprivate cachedWidth: number | undefined;\n\tprivate cachedLines: string[] | undefined;\n\n\tsetUI(ui: ExtensionUIContext): void {\n\t\tif (this.ui === ui) return;\n\t\tthis.dispose();\n\t\tthis.ui = ui;\n\t}\n\n\tresetVisibility(): void {\n\t\tthis.clearCompletionHideTimer();\n\t\tthis.knownStatuses.clear();\n\t\tthis.completedAt.clear();\n\t\tthis.hiddenCompleted.clear();\n\t\tthis.invalidateRenderCache();\n\t}\n\n\tupdate(): void {\n\t\tif (!this.ui) return;\n\t\tconst state = getTodoState();\n\t\tthis.syncVisibilityFromState(state);\n\t\tthis.invalidateRenderCache();\n\n\t\t// Register/unregister based on state, never as a render side effect.\n\t\tif (!hasVisibleOverlayItems(state, this.hiddenCompleted)) {\n\t\t\tif (this.registered) this.ui.setWidget(WIDGET_KEY, undefined);\n\t\t\tthis.registered = false;\n\t\t\tthis.tui = undefined;\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.registered) {\n\t\t\tthis.ui.setWidget(\n\t\t\t\tWIDGET_KEY,\n\t\t\t\t(tui, theme) => {\n\t\t\t\t\tthis.tui = tui;\n\t\t\t\t\treturn {\n\t\t\t\t\t\trender: (width: number) => this.render(theme, width),\n\t\t\t\t\t\tinvalidate: () => {\n\t\t\t\t\t\t\tthis.registered = false;\n\t\t\t\t\t\t\tthis.tui = undefined;\n\t\t\t\t\t\t\tthis.invalidateRenderCache();\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\t{ placement: \"aboveEditor\" },\n\t\t\t);\n\t\t\tthis.registered = true;\n\t\t\treturn;\n\t\t}\n\t\tthis.tui?.requestRender();\n\t}\n\n\t/** Track new completions for a short confirmation window; hide historical ones. */\n\tprivate syncVisibilityFromState(state: TodoState): void {\n\t\tconst now = Date.now();\n\t\tconst nextStatuses = new Map<number, TodoStatus>();\n\n\t\tfor (const item of state.items) {\n\t\t\tnextStatuses.set(item.id, item.status);\n\t\t\tconst previousStatus = this.knownStatuses.get(item.id);\n\t\t\tif (item.status !== \"completed\") {\n\t\t\t\tthis.completedAt.delete(item.id);\n\t\t\t\tthis.hiddenCompleted.delete(item.id);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (previousStatus === undefined) {\n\t\t\t\t// A replayed/reloaded completion is old from this overlay's point of\n\t\t\t\t// view. Keep the live surface focused on current work.\n\t\t\t\tthis.hiddenCompleted.add(item.id);\n\t\t\t\tthis.completedAt.delete(item.id);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (previousStatus !== \"completed\") {\n\t\t\t\tthis.completedAt.set(item.id, now);\n\t\t\t\tthis.hiddenCompleted.delete(item.id);\n\t\t\t}\n\t\t}\n\n\t\tfor (const id of this.knownStatuses.keys()) {\n\t\t\tif (nextStatuses.has(id)) continue;\n\t\t\tthis.completedAt.delete(id);\n\t\t\tthis.hiddenCompleted.delete(id);\n\t\t}\n\t\tthis.knownStatuses = nextStatuses;\n\n\t\tfor (const [id, completedAt] of this.completedAt) {\n\t\t\tif (now - completedAt < RECENT_COMPLETION_MS) continue;\n\t\t\tthis.completedAt.delete(id);\n\t\t\tthis.hiddenCompleted.add(id);\n\t\t}\n\t\tthis.scheduleCompletionHide();\n\t}\n\n\tprivate scheduleCompletionHide(): void {\n\t\tthis.clearCompletionHideTimer();\n\t\tlet earliestExpiry = Infinity;\n\t\tfor (const completedAt of this.completedAt.values()) {\n\t\t\tearliestExpiry = Math.min(earliestExpiry, completedAt + RECENT_COMPLETION_MS);\n\t\t}\n\t\tif (!Number.isFinite(earliestExpiry)) return;\n\n\t\tthis.completionHideTimer = setTimeout(\n\t\t\t() => {\n\t\t\t\tthis.completionHideTimer = undefined;\n\t\t\t\tthis.update();\n\t\t\t},\n\t\t\tMath.max(10, earliestExpiry - Date.now()),\n\t\t);\n\t}\n\n\tprivate clearCompletionHideTimer(): void {\n\t\tif (this.completionHideTimer === undefined) return;\n\t\tclearTimeout(this.completionHideTimer);\n\t\tthis.completionHideTimer = undefined;\n\t}\n\n\tprivate invalidateRenderCache(): void {\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\tprivate render(theme: Theme, width: number): string[] {\n\t\tconst normalizedWidth = Math.max(1, width);\n\t\tif (this.cachedLines !== undefined && this.cachedWidth === normalizedWidth) return this.cachedLines;\n\n\t\tconst lines = renderOverlayLines(getTodoState(), theme, normalizedWidth, this.hiddenCompleted);\n\t\tthis.cachedWidth = normalizedWidth;\n\t\tthis.cachedLines = lines;\n\t\treturn lines;\n\t}\n\n\tdispose(): void {\n\t\tthis.ui?.setWidget(WIDGET_KEY, undefined);\n\t\tthis.tui = undefined;\n\t\tthis.registered = false;\n\t\tthis.ui = undefined;\n\t\tthis.resetVisibility();\n\t}\n}\n"]}