wepscli 0.1.0
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/README.md +293 -0
- package/dist/WEPSCLI-shell/agent-runtime.js +824 -0
- package/dist/WEPSCLI-shell/agent-runtime.js.map +1 -0
- package/dist/WEPSCLI-shell/approval-overlay.js +275 -0
- package/dist/WEPSCLI-shell/approval-overlay.js.map +1 -0
- package/dist/WEPSCLI-shell/chat-components.js +760 -0
- package/dist/WEPSCLI-shell/chat-components.js.map +1 -0
- package/dist/WEPSCLI-shell/components.js +850 -0
- package/dist/WEPSCLI-shell/components.js.map +1 -0
- package/dist/WEPSCLI-shell/config-overlays.js +205 -0
- package/dist/WEPSCLI-shell/config-overlays.js.map +1 -0
- package/dist/WEPSCLI-shell/debug-log.js +16 -0
- package/dist/WEPSCLI-shell/debug-log.js.map +1 -0
- package/dist/WEPSCLI-shell/file-change-preview.js +261 -0
- package/dist/WEPSCLI-shell/file-change-preview.js.map +1 -0
- package/dist/WEPSCLI-shell/helpers.js +112 -0
- package/dist/WEPSCLI-shell/helpers.js.map +1 -0
- package/dist/WEPSCLI-shell/index.js +3 -0
- package/dist/WEPSCLI-shell/index.js.map +1 -0
- package/dist/WEPSCLI-shell/provider-add-flow.js +406 -0
- package/dist/WEPSCLI-shell/provider-add-flow.js.map +1 -0
- package/dist/WEPSCLI-shell/run-wepscli-shell.js +21 -0
- package/dist/WEPSCLI-shell/run-wepscli-shell.js.map +1 -0
- package/dist/WEPSCLI-shell/runtime-recovery.js +37 -0
- package/dist/WEPSCLI-shell/runtime-recovery.js.map +1 -0
- package/dist/WEPSCLI-shell/runtime-status.js +66 -0
- package/dist/WEPSCLI-shell/runtime-status.js.map +1 -0
- package/dist/WEPSCLI-shell/shell-app.js +1047 -0
- package/dist/WEPSCLI-shell/shell-app.js.map +1 -0
- package/dist/WEPSCLI-shell/shell-modes.js +77 -0
- package/dist/WEPSCLI-shell/shell-modes.js.map +1 -0
- package/dist/WEPSCLI-shell/slash-commands.js +135 -0
- package/dist/WEPSCLI-shell/slash-commands.js.map +1 -0
- package/dist/WEPSCLI-shell/theme.js +19 -0
- package/dist/WEPSCLI-shell/theme.js.map +1 -0
- package/dist/WEPSCLI-shell/tool-approval.js +85 -0
- package/dist/WEPSCLI-shell/tool-approval.js.map +1 -0
- package/dist/WEPSCLI-shell/tool-diff.js +76 -0
- package/dist/WEPSCLI-shell/tool-diff.js.map +1 -0
- package/dist/WEPSCLI-shell/tool-file-changes.js +268 -0
- package/dist/WEPSCLI-shell/tool-file-changes.js.map +1 -0
- package/dist/WEPSCLI-shell/tool-message-detail.js +138 -0
- package/dist/WEPSCLI-shell/tool-message-detail.js.map +1 -0
- package/dist/WEPSCLI-shell/tool-messages.js +145 -0
- package/dist/WEPSCLI-shell/tool-messages.js.map +1 -0
- package/dist/WEPSCLI-shell/transcript-panel.js +372 -0
- package/dist/WEPSCLI-shell/transcript-panel.js.map +1 -0
- package/dist/WEPSCLI-shell/transcript-state.js +62 -0
- package/dist/WEPSCLI-shell/transcript-state.js.map +1 -0
- package/dist/WEPSCLI-shell/types.js +1 -0
- package/dist/WEPSCLI-shell/types.js.map +1 -0
- package/dist/cli.js +11 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js +40 -0
- package/dist/config.js.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/main.js +140 -0
- package/dist/main.js.map +1 -0
- package/dist/onboarding/action-screen.js +90 -0
- package/dist/onboarding/action-screen.js.map +1 -0
- package/dist/onboarding/framed-screen.js +35 -0
- package/dist/onboarding/framed-screen.js.map +1 -0
- package/dist/onboarding/onboarding-app.js +312 -0
- package/dist/onboarding/onboarding-app.js.map +1 -0
- package/dist/onboarding/run-onboarding.js +23 -0
- package/dist/onboarding/run-onboarding.js.map +1 -0
- package/dist/onboarding/select-screen.js +21 -0
- package/dist/onboarding/select-screen.js.map +1 -0
- package/dist/onboarding/summary-screen.js +23 -0
- package/dist/onboarding/summary-screen.js.map +1 -0
- package/dist/onboarding/text-input-screen.js +55 -0
- package/dist/onboarding/text-input-screen.js.map +1 -0
- package/dist/onboarding/theme.js +26 -0
- package/dist/onboarding/theme.js.map +1 -0
- package/dist/provider-profiles/api-key-store.js +51 -0
- package/dist/provider-profiles/api-key-store.js.map +1 -0
- package/dist/provider-profiles/defaults.js +18 -0
- package/dist/provider-profiles/defaults.js.map +1 -0
- package/dist/provider-profiles/fetch-models.js +53 -0
- package/dist/provider-profiles/fetch-models.js.map +1 -0
- package/dist/provider-profiles/index.js +6 -0
- package/dist/provider-profiles/index.js.map +1 -0
- package/dist/provider-profiles/provider-profile-service.js +223 -0
- package/dist/provider-profiles/provider-profile-service.js.map +1 -0
- package/dist/provider-profiles/providers-config-store.js +17 -0
- package/dist/provider-profiles/providers-config-store.js.map +1 -0
- package/dist/provider-profiles/types.js +1 -0
- package/dist/provider-profiles/types.js.map +1 -0
- package/dist/session-history/session-history-service.js +142 -0
- package/dist/session-history/session-history-service.js.map +1 -0
- package/dist/shell/animator.js +30 -0
- package/dist/shell/animator.js.map +1 -0
- package/dist/shell/clickables.js +101 -0
- package/dist/shell/clickables.js.map +1 -0
- package/dist/shell/dashboard-shell.js +292 -0
- package/dist/shell/dashboard-shell.js.map +1 -0
- package/dist/shell/index.js +5 -0
- package/dist/shell/index.js.map +1 -0
- package/dist/shell/keymap.js +14 -0
- package/dist/shell/keymap.js.map +1 -0
- package/dist/shell/mouse.js +39 -0
- package/dist/shell/mouse.js.map +1 -0
- package/dist/shell/render.js +122 -0
- package/dist/shell/render.js.map +1 -0
- package/dist/shell/run-shell.js +36 -0
- package/dist/shell/run-shell.js.map +1 -0
- package/dist/shell/theme.js +56 -0
- package/dist/shell/theme.js.map +1 -0
- package/dist/storage/locked-json-file.js +88 -0
- package/dist/storage/locked-json-file.js.map +1 -0
- package/dist/workbench/animator.js +30 -0
- package/dist/workbench/animator.js.map +1 -0
- package/dist/workbench/index.js +6 -0
- package/dist/workbench/index.js.map +1 -0
- package/dist/workbench/mouse.js +39 -0
- package/dist/workbench/mouse.js.map +1 -0
- package/dist/workbench/render.js +82 -0
- package/dist/workbench/render.js.map +1 -0
- package/dist/workbench/renderer.js +364 -0
- package/dist/workbench/renderer.js.map +1 -0
- package/dist/workbench/run-workbench.js +36 -0
- package/dist/workbench/run-workbench.js.map +1 -0
- package/dist/workbench/theme.js +63 -0
- package/dist/workbench/theme.js.map +1 -0
- package/dist/workbench/types.js +1 -0
- package/dist/workbench/types.js.map +1 -0
- package/dist/workbench/workbench-shell.js +649 -0
- package/dist/workbench/workbench-shell.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
|
|
2
|
+
import { shellTheme } from "./theme.js";
|
|
3
|
+
function renderChipText(item) {
|
|
4
|
+
const base = `[ ${item.label} ]`;
|
|
5
|
+
switch (item.variant) {
|
|
6
|
+
case "active":
|
|
7
|
+
return shellTheme.accentStrong(base);
|
|
8
|
+
case "accent":
|
|
9
|
+
return shellTheme.accent(base);
|
|
10
|
+
case "success":
|
|
11
|
+
return shellTheme.success(base);
|
|
12
|
+
case "muted":
|
|
13
|
+
return shellTheme.muted(base);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function renderActionChips(items, width) {
|
|
17
|
+
const lines = [];
|
|
18
|
+
const regions = [];
|
|
19
|
+
let currentLine = "";
|
|
20
|
+
let currentWidth = 0;
|
|
21
|
+
let row = 0;
|
|
22
|
+
for (const item of items) {
|
|
23
|
+
const chip = renderChipText(item);
|
|
24
|
+
const chipWidth = visibleWidth(chip);
|
|
25
|
+
const gap = currentLine ? 1 : 0;
|
|
26
|
+
if (currentWidth + gap + chipWidth > width && currentLine) {
|
|
27
|
+
lines.push(currentLine);
|
|
28
|
+
currentLine = "";
|
|
29
|
+
currentWidth = 0;
|
|
30
|
+
row += 1;
|
|
31
|
+
}
|
|
32
|
+
const startCol = currentWidth + (currentLine ? 1 : 0);
|
|
33
|
+
currentLine += (currentLine ? " " : "") + chip;
|
|
34
|
+
currentWidth = visibleWidth(currentLine);
|
|
35
|
+
regions.push({
|
|
36
|
+
kind: "action",
|
|
37
|
+
id: item.id,
|
|
38
|
+
row,
|
|
39
|
+
col: startCol,
|
|
40
|
+
width: chipWidth,
|
|
41
|
+
height: 1
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
if (currentLine) {
|
|
45
|
+
lines.push(currentLine);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
lines,
|
|
49
|
+
regions
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function renderProviderButtons(profiles, selectedIndex, activeProfileId, width) {
|
|
53
|
+
const lines = [];
|
|
54
|
+
const regions = [];
|
|
55
|
+
const maxContentWidth = Math.max(8, width - 2);
|
|
56
|
+
profiles.forEach((profile, index) => {
|
|
57
|
+
const chips = [{
|
|
58
|
+
id: profile.id,
|
|
59
|
+
label: truncateToWidth(profile.label, 18, ""),
|
|
60
|
+
variant: index === selectedIndex ? "active" : "accent"
|
|
61
|
+
}, {
|
|
62
|
+
id: `${profile.id}:family`,
|
|
63
|
+
label: profile.family,
|
|
64
|
+
variant: "muted"
|
|
65
|
+
}, {
|
|
66
|
+
id: `${profile.id}:model`,
|
|
67
|
+
label: truncateToWidth(profile.models[0]?.id ?? "no-model", 18, ""),
|
|
68
|
+
variant: "muted"
|
|
69
|
+
}, {
|
|
70
|
+
id: `${profile.id}:state`,
|
|
71
|
+
label: activeProfileId === profile.id ? "ACTIVE" : "ACTIVATE",
|
|
72
|
+
variant: activeProfileId === profile.id ? "success" : "accent"
|
|
73
|
+
}];
|
|
74
|
+
let prefix = index === selectedIndex ? shellTheme.accentStrong("▶ ") : shellTheme.muted("• ");
|
|
75
|
+
let currentCol = visibleWidth(prefix);
|
|
76
|
+
let line = prefix;
|
|
77
|
+
for (let chipIndex = 0; chipIndex < chips.length; chipIndex++) {
|
|
78
|
+
const chipText = renderChipText(chips[chipIndex]);
|
|
79
|
+
const chipWidth = visibleWidth(chipText);
|
|
80
|
+
const gap = chipIndex === 0 ? 0 : 1;
|
|
81
|
+
if (currentCol + gap + chipWidth > maxContentWidth) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
line += (chipIndex === 0 ? "" : " ") + chipText;
|
|
85
|
+
regions.push({
|
|
86
|
+
kind: "provider",
|
|
87
|
+
id: profile.id,
|
|
88
|
+
row: index,
|
|
89
|
+
col: 0,
|
|
90
|
+
width: Math.min(maxContentWidth, visibleWidth(line)),
|
|
91
|
+
height: 1
|
|
92
|
+
});
|
|
93
|
+
currentCol = visibleWidth(line);
|
|
94
|
+
}
|
|
95
|
+
lines.push(line);
|
|
96
|
+
});
|
|
97
|
+
return {
|
|
98
|
+
lines,
|
|
99
|
+
regions
|
|
100
|
+
};
|
|
101
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["truncateToWidth","visibleWidth","shellTheme","renderChipText","item","base","label","variant","accentStrong","accent","success","muted","renderActionChips","items","width","lines","regions","currentLine","currentWidth","row","chip","chipWidth","gap","push","startCol","kind","id","col","height","renderProviderButtons","profiles","selectedIndex","activeProfileId","maxContentWidth","Math","max","forEach","profile","index","chips","family","models","prefix","currentCol","line","chipIndex","length","chipText","min"],"sources":["clickables.ts"],"sourcesContent":["import { truncateToWidth, visibleWidth } from \"@mariozechner/pi-tui\";\r\nimport type { ProviderProfile } from \"../provider-profiles/index.js\";\r\nimport { shellTheme } from \"./theme.js\";\r\n\r\nexport type ClickableKind = \"provider\" | \"action\";\r\n\r\nexport interface LocalClickableRegion {\r\n\tkind: ClickableKind;\r\n\tid: string;\r\n\trow: number;\r\n\tcol: number;\r\n\twidth: number;\r\n\theight: number;\r\n}\r\n\r\ninterface ChipItem {\r\n\tid: string;\r\n\tlabel: string;\r\n\tvariant: \"active\" | \"accent\" | \"muted\" | \"success\";\r\n}\r\n\r\nexport interface RenderedBlock {\r\n\tlines: string[];\r\n\tregions: LocalClickableRegion[];\r\n}\r\n\r\nfunction renderChipText(item: ChipItem): string {\r\n\tconst base = `[ ${item.label} ]`;\r\n\tswitch (item.variant) {\r\n\t\tcase \"active\":\r\n\t\t\treturn shellTheme.accentStrong(base);\r\n\t\tcase \"accent\":\r\n\t\t\treturn shellTheme.accent(base);\r\n\t\tcase \"success\":\r\n\t\t\treturn shellTheme.success(base);\r\n\t\tcase \"muted\":\r\n\t\t\treturn shellTheme.muted(base);\r\n\t}\r\n}\r\n\r\nexport function renderActionChips(items: ChipItem[], width: number): RenderedBlock {\r\n\tconst lines: string[] = [];\r\n\tconst regions: LocalClickableRegion[] = [];\r\n\tlet currentLine = \"\";\r\n\tlet currentWidth = 0;\r\n\tlet row = 0;\r\n\r\n\tfor (const item of items) {\r\n\t\tconst chip = renderChipText(item);\r\n\t\tconst chipWidth = visibleWidth(chip);\r\n\t\tconst gap = currentLine ? 1 : 0;\r\n\r\n\t\tif (currentWidth + gap + chipWidth > width && currentLine) {\r\n\t\t\tlines.push(currentLine);\r\n\t\t\tcurrentLine = \"\";\r\n\t\t\tcurrentWidth = 0;\r\n\t\t\trow += 1;\r\n\t\t}\r\n\r\n\t\tconst startCol = currentWidth + (currentLine ? 1 : 0);\r\n\t\tcurrentLine += (currentLine ? \" \" : \"\") + chip;\r\n\t\tcurrentWidth = visibleWidth(currentLine);\r\n\t\tregions.push({\r\n\t\t\tkind: \"action\",\r\n\t\t\tid: item.id,\r\n\t\t\trow,\r\n\t\t\tcol: startCol,\r\n\t\t\twidth: chipWidth,\r\n\t\t\theight: 1,\r\n\t\t});\r\n\t}\r\n\r\n\tif (currentLine) {\r\n\t\tlines.push(currentLine);\r\n\t}\r\n\r\n\treturn { lines, regions };\r\n}\r\n\r\nexport function renderProviderButtons(\r\n\tprofiles: ProviderProfile[],\r\n\tselectedIndex: number,\r\n\tactiveProfileId: string | undefined,\r\n\twidth: number,\r\n): RenderedBlock {\r\n\tconst lines: string[] = [];\r\n\tconst regions: LocalClickableRegion[] = [];\r\n\tconst maxContentWidth = Math.max(8, width - 2);\r\n\r\n\tprofiles.forEach((profile, index) => {\r\n\t\tconst chips: ChipItem[] = [\r\n\t\t\t{\r\n\t\t\t\tid: profile.id,\r\n\t\t\t\tlabel: truncateToWidth(profile.label, 18, \"\"),\r\n\t\t\t\tvariant: index === selectedIndex ? \"active\" : \"accent\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tid: `${profile.id}:family`,\r\n\t\t\t\tlabel: profile.family,\r\n\t\t\t\tvariant: \"muted\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tid: `${profile.id}:model`,\r\n\t\t\t\tlabel: truncateToWidth(profile.models[0]?.id ?? \"no-model\", 18, \"\"),\r\n\t\t\t\tvariant: \"muted\",\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t\tid: `${profile.id}:state`,\r\n\t\t\t\tlabel: activeProfileId === profile.id ? \"ACTIVE\" : \"ACTIVATE\",\r\n\t\t\t\tvariant: activeProfileId === profile.id ? \"success\" : \"accent\",\r\n\t\t\t},\r\n\t\t];\r\n\r\n\t\tlet prefix = index === selectedIndex ? shellTheme.accentStrong(\"▶ \") : shellTheme.muted(\"• \");\r\n\t\tlet currentCol = visibleWidth(prefix);\r\n\t\tlet line = prefix;\r\n\r\n\t\tfor (let chipIndex = 0; chipIndex < chips.length; chipIndex++) {\r\n\t\t\tconst chipText = renderChipText(chips[chipIndex]!);\r\n\t\t\tconst chipWidth = visibleWidth(chipText);\r\n\t\t\tconst gap = chipIndex === 0 ? 0 : 1;\r\n\t\t\tif (currentCol + gap + chipWidth > maxContentWidth) {\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tline += (chipIndex === 0 ? \"\" : \" \") + chipText;\r\n\t\t\tregions.push({\r\n\t\t\t\tkind: \"provider\",\r\n\t\t\t\tid: profile.id,\r\n\t\t\t\trow: index,\r\n\t\t\t\tcol: 0,\r\n\t\t\t\twidth: Math.min(maxContentWidth, visibleWidth(line)),\r\n\t\t\t\theight: 1,\r\n\t\t\t});\r\n\t\t\tcurrentCol = visibleWidth(line);\r\n\t\t}\r\n\r\n\t\tlines.push(line);\r\n\t});\r\n\r\n\treturn { lines, regions };\r\n}\r\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { getKeybindings, Input, Key, matchesKey } from "@mariozechner/pi-tui";
|
|
2
|
+
import { getAgentDir } from "../config.js";
|
|
3
|
+
import { ShellAnimator } from "./animator.js";
|
|
4
|
+
import { renderActionChips, renderProviderButtons } from "./clickables.js";
|
|
5
|
+
import { getFocusLabel, shellKeymap } from "./keymap.js";
|
|
6
|
+
import { computeShellLayout, fitLines, framePanelFixed, joinColumns, padLine } from "./render.js";
|
|
7
|
+
import { getPanelStyle, pulseDot, shellTheme, shimmerText } from "./theme.js";
|
|
8
|
+
export class DashboardShell {
|
|
9
|
+
composer = new Input();
|
|
10
|
+
timeline = [];
|
|
11
|
+
profiles = [];
|
|
12
|
+
selectedProviderIndex = 0;
|
|
13
|
+
focusRegion = "composer";
|
|
14
|
+
actionRegions = [];
|
|
15
|
+
providerRegions = [];
|
|
16
|
+
_focused = false;
|
|
17
|
+
constructor(ui, profileService, onExit) {
|
|
18
|
+
this.ui = ui;
|
|
19
|
+
this.profileService = profileService;
|
|
20
|
+
this.onExit = onExit;
|
|
21
|
+
this.animator = new ShellAnimator(ui);
|
|
22
|
+
this.reloadProfiles();
|
|
23
|
+
this.composer.onSubmit = value => {
|
|
24
|
+
const trimmed = value.trim();
|
|
25
|
+
if (!trimmed) return;
|
|
26
|
+
this.timeline.unshift(`Draft queued: ${trimmed}`);
|
|
27
|
+
this.composer.setValue("");
|
|
28
|
+
this.ui.requestRender();
|
|
29
|
+
};
|
|
30
|
+
this.composer.onEscape = () => {
|
|
31
|
+
if (!this.composer.getValue().trim()) {
|
|
32
|
+
this.onExit();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
get focused() {
|
|
37
|
+
return this._focused;
|
|
38
|
+
}
|
|
39
|
+
set focused(value) {
|
|
40
|
+
this._focused = value;
|
|
41
|
+
this.composer.focused = value && this.focusRegion === "composer";
|
|
42
|
+
}
|
|
43
|
+
dispose() {
|
|
44
|
+
this.animator.dispose();
|
|
45
|
+
}
|
|
46
|
+
invalidate() {
|
|
47
|
+
this.composer.invalidate();
|
|
48
|
+
}
|
|
49
|
+
handleInput(data) {
|
|
50
|
+
const kb = getKeybindings();
|
|
51
|
+
if (matchesKey(data, Key.ctrl("c"))) {
|
|
52
|
+
this.onExit();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (kb.matches(data, "tui.input.tab")) {
|
|
56
|
+
this.focusRegion = this.focusRegion === "composer" ? "workspace" : "composer";
|
|
57
|
+
this.composer.focused = this._focused && this.focusRegion === "composer";
|
|
58
|
+
this.animator.markFocusPulse();
|
|
59
|
+
this.ui.requestRender();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (this.focusRegion === "workspace") {
|
|
63
|
+
this.handleWorkspaceInput(data);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.composer.handleInput(data);
|
|
67
|
+
}
|
|
68
|
+
handleMouseEvent(event) {
|
|
69
|
+
if (event.action === "scroll") {
|
|
70
|
+
if (this.hitAny(event.col, event.row, this.providerRegions)) {
|
|
71
|
+
const delta = event.button === "wheel-up" ? -1 : event.button === "wheel-down" ? 1 : 0;
|
|
72
|
+
if (delta !== 0) {
|
|
73
|
+
this.moveProviderSelection(delta);
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
const actionTarget = this.findHit(event.col, event.row, this.actionRegions);
|
|
80
|
+
if (actionTarget && this.isPrimaryMouseActivation(event)) {
|
|
81
|
+
this.activateAction(actionTarget.id);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
const providerTarget = this.findHit(event.col, event.row, this.providerRegions);
|
|
85
|
+
if (providerTarget && this.isPrimaryMouseActivation(event)) {
|
|
86
|
+
this.focusRegion = "workspace";
|
|
87
|
+
this.composer.focused = false;
|
|
88
|
+
this.animator.markFocusPulse();
|
|
89
|
+
this.activateProviderById(providerTarget.id);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
if (this.composerInputRegion && this.pointInRect(event.col, event.row, this.composerInputRegion)) {
|
|
93
|
+
if (this.isPrimaryMouseActivation(event)) {
|
|
94
|
+
this.focusRegion = "composer";
|
|
95
|
+
this.composer.focused = this._focused;
|
|
96
|
+
this.animator.markFocusPulse();
|
|
97
|
+
this.ui.requestRender();
|
|
98
|
+
}
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
render(width) {
|
|
104
|
+
this.reloadProfiles();
|
|
105
|
+
const height = this.ui.terminal.rows;
|
|
106
|
+
const layout = computeShellLayout(width, height);
|
|
107
|
+
const animation = this.animator.getSnapshot();
|
|
108
|
+
const headerLines = fitLines([shellTheme.headerBackground(` ${shimmerText("WEPSCLI DASHBOARD", animation.frame)} `), shellTheme.headerBackground(padLine(shellTheme.muted(` Focus ${shellTheme.accent(getFocusLabel(this.focusRegion))} | Provider cards ${shellTheme.accent(shellKeymap.navigate)} ${shellTheme.accent(shellKeymap.select)} | Focus switch ${shellTheme.accent(shellKeymap.switchFocus)} `), width)), shellTheme.headerBackground(padLine(shellTheme.muted(` Config root ${getAgentDir()} `), width))], width, layout.headerHeight);
|
|
109
|
+
this.actionRegions = [];
|
|
110
|
+
this.providerRegions = [];
|
|
111
|
+
this.composerInputRegion = undefined;
|
|
112
|
+
const mainLines = animation.showMain ? this.renderMainPanel(layout.mainWidth, layout.bodyHeight, animation.frame, animation.focusPulseActive, layout.headerHeight) : fitLines([shimmerText("Booting workspace surface...", animation.frame)], layout.mainWidth, layout.bodyHeight);
|
|
113
|
+
const statusLines = layout.showStatusPanel ? animation.showStatus ? this.renderStatusPanel(layout.statusWidth, layout.bodyHeight, animation.frame, animation.focusPulseActive) : fitLines([shimmerText("Initializing status surface...", animation.frame + 4)], layout.statusWidth, layout.bodyHeight) : [];
|
|
114
|
+
const bodyLines = layout.showStatusPanel ? joinColumns(mainLines, layout.mainWidth, statusLines, layout.statusWidth, layout.gap) : mainLines;
|
|
115
|
+
const dockLines = animation.showDock ? this.renderDock(width, layout.dockHeight, animation.focusPulseActive, layout.headerHeight + layout.bodyHeight) : fitLines([shimmerText("Preparing composer dock...", animation.frame + 8)], width, layout.dockHeight);
|
|
116
|
+
return [...headerLines, ...bodyLines, ...dockLines];
|
|
117
|
+
}
|
|
118
|
+
handleWorkspaceInput(data) {
|
|
119
|
+
const kb = getKeybindings();
|
|
120
|
+
if (kb.matches(data, "tui.select.cancel")) {
|
|
121
|
+
this.onExit();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (kb.matches(data, "tui.select.up")) {
|
|
125
|
+
this.moveProviderSelection(-1);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (kb.matches(data, "tui.select.down")) {
|
|
129
|
+
this.moveProviderSelection(1);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (kb.matches(data, "tui.select.confirm")) {
|
|
133
|
+
const profile = this.profiles[this.selectedProviderIndex];
|
|
134
|
+
if (profile) {
|
|
135
|
+
this.switchActiveProfile(profile);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
reloadProfiles() {
|
|
140
|
+
this.profiles = this.profileService.listProfiles();
|
|
141
|
+
if (this.profiles.length === 0) {
|
|
142
|
+
this.selectedProviderIndex = 0;
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const selection = this.profileService.getActiveSelection();
|
|
146
|
+
const activeIndex = selection.profileId ? this.profiles.findIndex(item => item.id === selection.profileId) : -1;
|
|
147
|
+
if (activeIndex >= 0 && (this.selectedProviderIndex < 0 || this.selectedProviderIndex >= this.profiles.length)) {
|
|
148
|
+
this.selectedProviderIndex = activeIndex;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (activeIndex >= 0 && this.selectedProviderIndex === 0 && this.profiles.length === 1) {
|
|
152
|
+
this.selectedProviderIndex = activeIndex;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
this.selectedProviderIndex = Math.max(0, Math.min(this.selectedProviderIndex, this.profiles.length - 1));
|
|
156
|
+
}
|
|
157
|
+
moveProviderSelection(delta) {
|
|
158
|
+
if (this.profiles.length === 0) return;
|
|
159
|
+
const next = this.selectedProviderIndex + delta;
|
|
160
|
+
if (next < 0) {
|
|
161
|
+
this.selectedProviderIndex = this.profiles.length - 1;
|
|
162
|
+
} else if (next >= this.profiles.length) {
|
|
163
|
+
this.selectedProviderIndex = 0;
|
|
164
|
+
} else {
|
|
165
|
+
this.selectedProviderIndex = next;
|
|
166
|
+
}
|
|
167
|
+
this.focusRegion = "workspace";
|
|
168
|
+
this.composer.focused = false;
|
|
169
|
+
this.animator.markFocusPulse();
|
|
170
|
+
this.ui.requestRender();
|
|
171
|
+
}
|
|
172
|
+
renderMainPanel(width, height, frame, focusPulseActive, headerHeight) {
|
|
173
|
+
const innerWidth = Math.max(1, width - 2);
|
|
174
|
+
const selection = this.profileService.getActiveSelection();
|
|
175
|
+
const activeProfile = selection.profileId ? this.profiles.find(item => item.id === selection.profileId) : undefined;
|
|
176
|
+
const providerRows = renderProviderButtons(this.profiles, this.selectedProviderIndex, selection.profileId, innerWidth);
|
|
177
|
+
const body = [shellTheme.accent("Workspace"), padLine(activeProfile ? shellTheme.text(`Current provider: ${activeProfile.label} (${activeProfile.family})`) : shellTheme.warning("No active provider selected."), innerWidth), padLine(selection.modelId ? shellTheme.text(`Current model: ${selection.modelId}`) : shellTheme.text("Current model: none"), innerWidth), padLine(shellTheme.muted("Provider entries below are the actual switch controls. Click a row or press Enter."), innerWidth), "", padLine(shellTheme.accent(`Provider Controls ${shellTheme.accentSoft(`[${pulseDot(frame)}]`)}`), innerWidth), ...providerRows.lines.map(line => padLine(line, innerWidth)), "", padLine(shellTheme.accent("Timeline"), innerWidth), ...(this.timeline.length > 0 ? this.timeline.slice(0, Math.max(1, height - 12)).map(line => padLine(shellTheme.text(line), innerWidth)) : [padLine(shellTheme.muted("No local dashboard activity yet. Use the composer below to populate this timeline."), innerWidth)])];
|
|
178
|
+
const panelTopRow = headerHeight + 1;
|
|
179
|
+
const providerBaseRow = panelTopRow + 1 + 6;
|
|
180
|
+
this.providerRegions = providerRows.regions.map(region => ({
|
|
181
|
+
...region,
|
|
182
|
+
row: providerBaseRow + region.row,
|
|
183
|
+
col: 2
|
|
184
|
+
}));
|
|
185
|
+
return framePanelFixed(this.focusRegion === "workspace" ? "Main Workspace [active]" : "Main Workspace", body, width, height, getPanelStyle("main", this.focusRegion === "workspace", this.focusRegion === "workspace" && focusPulseActive));
|
|
186
|
+
}
|
|
187
|
+
renderStatusPanel(width, height, frame, focusPulseActive) {
|
|
188
|
+
const innerWidth = Math.max(1, width - 2);
|
|
189
|
+
const selection = this.profileService.getActiveSelection();
|
|
190
|
+
const activeProfile = selection.profileId ? this.profiles.find(item => item.id === selection.profileId) : undefined;
|
|
191
|
+
const body = [padLine(shellTheme.accent("State"), innerWidth), padLine(shellTheme.success(`Task status: idle ${pulseDot(frame)}`), innerWidth), padLine(shellTheme.text("Mode: solo"), innerWidth), "", padLine(shellTheme.accent("Context"), innerWidth), padLine(shellTheme.text("Usage: stub"), innerWidth), padLine(shellTheme.text("Window: stub"), innerWidth), "", padLine(shellTheme.accent("Todo"), innerWidth), padLine(shellTheme.text("1. Hook dashboard into real session history"), innerWidth), padLine(shellTheme.text("2. Replace local draft timeline with agent timeline"), innerWidth), padLine(shellTheme.text("3. Wire mode/model/session controls into dock dialogs"), innerWidth), "", padLine(shellTheme.accent("Selection"), innerWidth), padLine(shellTheme.text(`Provider: ${activeProfile?.label ?? "none"}`), innerWidth), padLine(shellTheme.text(`Model: ${selection.modelId ?? "none"}`), innerWidth)];
|
|
192
|
+
return framePanelFixed("Status Panel", body, width, height, getPanelStyle("status", false, focusPulseActive));
|
|
193
|
+
}
|
|
194
|
+
renderDock(width, height, focusPulseActive, bodyStartRow) {
|
|
195
|
+
const innerWidth = Math.max(1, width - 2);
|
|
196
|
+
const selection = this.profileService.getActiveSelection();
|
|
197
|
+
const activeProfile = selection.profileId ? this.profiles.find(item => item.id === selection.profileId) : undefined;
|
|
198
|
+
const actionChips = renderActionChips([{
|
|
199
|
+
id: "provider",
|
|
200
|
+
label: `Provider: ${activeProfile?.label ?? "none"}`,
|
|
201
|
+
variant: "accent"
|
|
202
|
+
}, {
|
|
203
|
+
id: "model",
|
|
204
|
+
label: `Model: ${selection.modelId ?? "none"}`,
|
|
205
|
+
variant: "muted"
|
|
206
|
+
}, {
|
|
207
|
+
id: "mode",
|
|
208
|
+
label: "Mode: solo",
|
|
209
|
+
variant: "muted"
|
|
210
|
+
}, {
|
|
211
|
+
id: "session",
|
|
212
|
+
label: "Session",
|
|
213
|
+
variant: "muted"
|
|
214
|
+
}, {
|
|
215
|
+
id: "focus",
|
|
216
|
+
label: "Focus Composer",
|
|
217
|
+
variant: "active"
|
|
218
|
+
}], innerWidth);
|
|
219
|
+
const composerLines = this.composer.render(innerWidth);
|
|
220
|
+
const actionBaseRow = bodyStartRow + 1;
|
|
221
|
+
this.actionRegions = actionChips.regions.map(region => ({
|
|
222
|
+
...region,
|
|
223
|
+
row: actionBaseRow + region.row,
|
|
224
|
+
col: 2 + region.col
|
|
225
|
+
}));
|
|
226
|
+
const composerRowOffset = actionChips.lines.length + 2;
|
|
227
|
+
this.composerInputRegion = {
|
|
228
|
+
row: bodyStartRow + 1 + composerRowOffset,
|
|
229
|
+
col: 2,
|
|
230
|
+
width: innerWidth,
|
|
231
|
+
height: Math.max(1, composerLines.length)
|
|
232
|
+
};
|
|
233
|
+
const body = [...actionChips.lines.map(line => padLine(line, innerWidth)), "", padLine(shellTheme.accent("Composer"), innerWidth), ...composerLines.map(line => padLine(line, innerWidth)), padLine(shellTheme.muted(`Focus ${getFocusLabel(this.focusRegion)} | Use the chips above as explicit controls`), innerWidth), padLine(shellTheme.muted(`Keys: ${shellKeymap.switchFocus} focus | ${shellKeymap.select} select/submit | ${shellKeymap.exit} exit`), innerWidth)];
|
|
234
|
+
return framePanelFixed(this.focusRegion === "composer" ? "Bottom Dock [active]" : "Bottom Dock", body, width, height, getPanelStyle("dock", this.focusRegion === "composer", this.focusRegion === "composer" && focusPulseActive));
|
|
235
|
+
}
|
|
236
|
+
activateProviderById(profileId) {
|
|
237
|
+
const index = this.profiles.findIndex(item => item.id === profileId);
|
|
238
|
+
if (index === -1) return;
|
|
239
|
+
this.selectedProviderIndex = index;
|
|
240
|
+
this.switchActiveProfile(this.profiles[index]);
|
|
241
|
+
}
|
|
242
|
+
activateAction(actionId) {
|
|
243
|
+
switch (actionId) {
|
|
244
|
+
case "focus":
|
|
245
|
+
this.focusRegion = "composer";
|
|
246
|
+
this.composer.focused = this._focused;
|
|
247
|
+
this.timeline.unshift("Composer focus selected from dock controls.");
|
|
248
|
+
break;
|
|
249
|
+
case "provider":
|
|
250
|
+
this.focusRegion = "workspace";
|
|
251
|
+
this.composer.focused = false;
|
|
252
|
+
this.timeline.unshift("Provider control selected. Use provider rows to switch explicitly.");
|
|
253
|
+
break;
|
|
254
|
+
case "model":
|
|
255
|
+
this.timeline.unshift("Model dialog placeholder selected. UI wiring comes next.");
|
|
256
|
+
break;
|
|
257
|
+
case "mode":
|
|
258
|
+
this.timeline.unshift("Mode dialog placeholder selected. UI wiring comes next.");
|
|
259
|
+
break;
|
|
260
|
+
case "session":
|
|
261
|
+
this.timeline.unshift("Session control placeholder selected. UI wiring comes next.");
|
|
262
|
+
break;
|
|
263
|
+
default:
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
this.animator.markFocusPulse();
|
|
267
|
+
this.ui.requestRender();
|
|
268
|
+
}
|
|
269
|
+
findHit(col, row, regions) {
|
|
270
|
+
return regions.find(region => this.pointInRect(col, row, region));
|
|
271
|
+
}
|
|
272
|
+
hitAny(col, row, regions) {
|
|
273
|
+
return this.findHit(col, row, regions) !== undefined;
|
|
274
|
+
}
|
|
275
|
+
pointInRect(col, row, rect) {
|
|
276
|
+
return col >= rect.col && col < rect.col + rect.width && row >= rect.row && row < rect.row + rect.height;
|
|
277
|
+
}
|
|
278
|
+
isPrimaryMouseActivation(event) {
|
|
279
|
+
return event.button === "left" && (event.action === "press" || event.action === "release");
|
|
280
|
+
}
|
|
281
|
+
switchActiveProfile(profile) {
|
|
282
|
+
const selection = this.profileService.getActiveSelection();
|
|
283
|
+
const nextModel = profile.models[0]?.id;
|
|
284
|
+
const isSameSelection = selection.profileId === profile.id && selection.modelId === nextModel;
|
|
285
|
+
if (!isSameSelection) {
|
|
286
|
+
this.profileService.setActiveSelection(profile.id, nextModel);
|
|
287
|
+
this.timeline.unshift(`Active provider switched to ${profile.label}${nextModel ? ` (${nextModel})` : ""}`);
|
|
288
|
+
}
|
|
289
|
+
this.animator.markFocusPulse();
|
|
290
|
+
this.ui.requestRender();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["getKeybindings","Input","Key","matchesKey","getAgentDir","ShellAnimator","renderActionChips","renderProviderButtons","getFocusLabel","shellKeymap","computeShellLayout","fitLines","framePanelFixed","joinColumns","padLine","getPanelStyle","pulseDot","shellTheme","shimmerText","DashboardShell","composer","timeline","profiles","selectedProviderIndex","focusRegion","actionRegions","providerRegions","_focused","constructor","ui","profileService","onExit","animator","reloadProfiles","onSubmit","value","trimmed","trim","unshift","setValue","requestRender","onEscape","getValue","focused","dispose","invalidate","handleInput","data","kb","ctrl","matches","markFocusPulse","handleWorkspaceInput","handleMouseEvent","event","action","hitAny","col","row","delta","button","moveProviderSelection","actionTarget","findHit","isPrimaryMouseActivation","activateAction","id","providerTarget","activateProviderById","composerInputRegion","pointInRect","render","width","height","terminal","rows","layout","animation","getSnapshot","headerLines","headerBackground","frame","muted","accent","navigate","select","switchFocus","headerHeight","undefined","mainLines","showMain","renderMainPanel","mainWidth","bodyHeight","focusPulseActive","statusLines","showStatusPanel","showStatus","renderStatusPanel","statusWidth","bodyLines","gap","dockLines","showDock","renderDock","dockHeight","profile","switchActiveProfile","listProfiles","length","selection","getActiveSelection","activeIndex","profileId","findIndex","item","Math","max","min","next","innerWidth","activeProfile","find","providerRows","body","text","label","family","warning","modelId","accentSoft","lines","map","line","slice","panelTopRow","providerBaseRow","regions","region","success","bodyStartRow","actionChips","variant","composerLines","actionBaseRow","composerRowOffset","exit","index","actionId","rect","nextModel","models","isSameSelection","setActiveSelection"],"sources":["dashboard-shell.ts"],"sourcesContent":["import { type Component, type Focusable, getKeybindings, Input, Key, matchesKey, type TUI } from \"@mariozechner/pi-tui\";\r\nimport { getAgentDir } from \"../config.js\";\r\nimport { type ProviderProfile, ProviderProfileService } from \"../provider-profiles/index.js\";\r\nimport { ShellAnimator } from \"./animator.js\";\r\nimport { type LocalClickableRegion, renderActionChips, renderProviderButtons } from \"./clickables.js\";\r\nimport { getFocusLabel, type ShellFocusRegion, shellKeymap } from \"./keymap.js\";\r\nimport type { ParsedMouseEvent } from \"./mouse.js\";\r\nimport { computeShellLayout, fitLines, framePanelFixed, joinColumns, padLine } from \"./render.js\";\r\nimport { getPanelStyle, pulseDot, shellTheme, shimmerText } from \"./theme.js\";\r\n\r\ninterface GlobalClickableRegion extends LocalClickableRegion {\r\n\trow: number;\r\n\tcol: number;\r\n}\r\n\r\nexport class DashboardShell implements Component, Focusable {\r\n\tprivate readonly composer = new Input();\r\n\tprivate readonly timeline: string[] = [];\r\n\tprivate readonly animator: ShellAnimator;\r\n\tprivate profiles: ProviderProfile[] = [];\r\n\tprivate selectedProviderIndex = 0;\r\n\tprivate focusRegion: ShellFocusRegion = \"composer\";\r\n\tprivate actionRegions: GlobalClickableRegion[] = [];\r\n\tprivate providerRegions: GlobalClickableRegion[] = [];\r\n\tprivate composerInputRegion?: { row: number; col: number; width: number; height: number };\r\n\tprivate _focused = false;\r\n\r\n\tconstructor(\r\n\t\tprivate readonly ui: TUI,\r\n\t\tprivate readonly profileService: ProviderProfileService,\r\n\t\tprivate readonly onExit: () => void,\r\n\t) {\r\n\t\tthis.animator = new ShellAnimator(ui);\r\n\t\tthis.reloadProfiles();\r\n\r\n\t\tthis.composer.onSubmit = (value) => {\r\n\t\t\tconst trimmed = value.trim();\r\n\t\t\tif (!trimmed) return;\r\n\t\t\tthis.timeline.unshift(`Draft queued: ${trimmed}`);\r\n\t\t\tthis.composer.setValue(\"\");\r\n\t\t\tthis.ui.requestRender();\r\n\t\t};\r\n\r\n\t\tthis.composer.onEscape = () => {\r\n\t\t\tif (!this.composer.getValue().trim()) {\r\n\t\t\t\tthis.onExit();\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\tget focused(): boolean {\r\n\t\treturn this._focused;\r\n\t}\r\n\r\n\tset focused(value: boolean) {\r\n\t\tthis._focused = value;\r\n\t\tthis.composer.focused = value && this.focusRegion === \"composer\";\r\n\t}\r\n\r\n\tdispose(): void {\r\n\t\tthis.animator.dispose();\r\n\t}\r\n\r\n\tinvalidate(): void {\r\n\t\tthis.composer.invalidate();\r\n\t}\r\n\r\n\thandleInput(data: string): void {\r\n\t\tconst kb = getKeybindings();\r\n\t\tif (matchesKey(data, Key.ctrl(\"c\"))) {\r\n\t\t\tthis.onExit();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (kb.matches(data, \"tui.input.tab\")) {\r\n\t\t\tthis.focusRegion = this.focusRegion === \"composer\" ? \"workspace\" : \"composer\";\r\n\t\t\tthis.composer.focused = this._focused && this.focusRegion === \"composer\";\r\n\t\t\tthis.animator.markFocusPulse();\r\n\t\t\tthis.ui.requestRender();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (this.focusRegion === \"workspace\") {\r\n\t\t\tthis.handleWorkspaceInput(data);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.composer.handleInput(data);\r\n\t}\r\n\r\n\thandleMouseEvent(event: ParsedMouseEvent): boolean {\r\n\t\tif (event.action === \"scroll\") {\r\n\t\t\tif (this.hitAny(event.col, event.row, this.providerRegions)) {\r\n\t\t\t\tconst delta = event.button === \"wheel-up\" ? -1 : event.button === \"wheel-down\" ? 1 : 0;\r\n\t\t\t\tif (delta !== 0) {\r\n\t\t\t\t\tthis.moveProviderSelection(delta);\r\n\t\t\t\t}\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tconst actionTarget = this.findHit(event.col, event.row, this.actionRegions);\r\n\t\tif (actionTarget && this.isPrimaryMouseActivation(event)) {\r\n\t\t\tthis.activateAction(actionTarget.id);\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tconst providerTarget = this.findHit(event.col, event.row, this.providerRegions);\r\n\t\tif (providerTarget && this.isPrimaryMouseActivation(event)) {\r\n\t\t\tthis.focusRegion = \"workspace\";\r\n\t\t\tthis.composer.focused = false;\r\n\t\t\tthis.animator.markFocusPulse();\r\n\t\t\tthis.activateProviderById(providerTarget.id);\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tif (this.composerInputRegion && this.pointInRect(event.col, event.row, this.composerInputRegion)) {\r\n\t\t\tif (this.isPrimaryMouseActivation(event)) {\r\n\t\t\t\tthis.focusRegion = \"composer\";\r\n\t\t\t\tthis.composer.focused = this._focused;\r\n\t\t\t\tthis.animator.markFocusPulse();\r\n\t\t\t\tthis.ui.requestRender();\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\trender(width: number): string[] {\r\n\t\tthis.reloadProfiles();\r\n\t\tconst height = this.ui.terminal.rows;\r\n\t\tconst layout = computeShellLayout(width, height);\r\n\t\tconst animation = this.animator.getSnapshot();\r\n\r\n\t\tconst headerLines = fitLines(\r\n\t\t\t[\r\n\t\t\t\tshellTheme.headerBackground(` ${shimmerText(\"WEPSCLI DASHBOARD\", animation.frame)} `),\r\n\t\t\t\tshellTheme.headerBackground(\r\n\t\t\t\t\tpadLine(\r\n\t\t\t\t\t\tshellTheme.muted(\r\n\t\t\t\t\t\t\t` Focus ${shellTheme.accent(getFocusLabel(this.focusRegion))} | Provider cards ${shellTheme.accent(shellKeymap.navigate)} ${shellTheme.accent(shellKeymap.select)} | Focus switch ${shellTheme.accent(shellKeymap.switchFocus)} `,\r\n\t\t\t\t\t\t),\r\n\t\t\t\t\t\twidth,\r\n\t\t\t\t\t),\r\n\t\t\t\t),\r\n\t\t\t\tshellTheme.headerBackground(padLine(shellTheme.muted(` Config root ${getAgentDir()} `), width)),\r\n\t\t\t],\r\n\t\t\twidth,\r\n\t\t\tlayout.headerHeight,\r\n\t\t);\r\n\r\n\t\tthis.actionRegions = [];\r\n\t\tthis.providerRegions = [];\r\n\t\tthis.composerInputRegion = undefined;\r\n\r\n\t\tconst mainLines = animation.showMain\r\n\t\t\t? this.renderMainPanel(layout.mainWidth, layout.bodyHeight, animation.frame, animation.focusPulseActive, layout.headerHeight)\r\n\t\t\t: fitLines([shimmerText(\"Booting workspace surface...\", animation.frame)], layout.mainWidth, layout.bodyHeight);\r\n\r\n\t\tconst statusLines = layout.showStatusPanel\r\n\t\t\t? animation.showStatus\r\n\t\t\t\t? this.renderStatusPanel(layout.statusWidth, layout.bodyHeight, animation.frame, animation.focusPulseActive)\r\n\t\t\t\t: fitLines([shimmerText(\"Initializing status surface...\", animation.frame + 4)], layout.statusWidth, layout.bodyHeight)\r\n\t\t\t: [];\r\n\r\n\t\tconst bodyLines = layout.showStatusPanel\r\n\t\t\t? joinColumns(mainLines, layout.mainWidth, statusLines, layout.statusWidth, layout.gap)\r\n\t\t\t: mainLines;\r\n\r\n\t\tconst dockLines = animation.showDock\r\n\t\t\t? this.renderDock(width, layout.dockHeight, animation.focusPulseActive, layout.headerHeight + layout.bodyHeight)\r\n\t\t\t: fitLines([shimmerText(\"Preparing composer dock...\", animation.frame + 8)], width, layout.dockHeight);\r\n\r\n\t\treturn [...headerLines, ...bodyLines, ...dockLines];\r\n\t}\r\n\r\n\tprivate handleWorkspaceInput(data: string): void {\r\n\t\tconst kb = getKeybindings();\r\n\t\tif (kb.matches(data, \"tui.select.cancel\")) {\r\n\t\t\tthis.onExit();\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (kb.matches(data, \"tui.select.up\")) {\r\n\t\t\tthis.moveProviderSelection(-1);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (kb.matches(data, \"tui.select.down\")) {\r\n\t\t\tthis.moveProviderSelection(1);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (kb.matches(data, \"tui.select.confirm\")) {\r\n\t\t\tconst profile = this.profiles[this.selectedProviderIndex];\r\n\t\t\tif (profile) {\r\n\t\t\t\tthis.switchActiveProfile(profile);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tprivate reloadProfiles(): void {\r\n\t\tthis.profiles = this.profileService.listProfiles();\r\n\t\tif (this.profiles.length === 0) {\r\n\t\t\tthis.selectedProviderIndex = 0;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst selection = this.profileService.getActiveSelection();\r\n\t\tconst activeIndex = selection.profileId ? this.profiles.findIndex((item) => item.id === selection.profileId) : -1;\r\n\t\tif (activeIndex >= 0 && (this.selectedProviderIndex < 0 || this.selectedProviderIndex >= this.profiles.length)) {\r\n\t\t\tthis.selectedProviderIndex = activeIndex;\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (activeIndex >= 0 && this.selectedProviderIndex === 0 && this.profiles.length === 1) {\r\n\t\t\tthis.selectedProviderIndex = activeIndex;\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tthis.selectedProviderIndex = Math.max(0, Math.min(this.selectedProviderIndex, this.profiles.length - 1));\r\n\t}\r\n\r\n\tprivate moveProviderSelection(delta: number): void {\r\n\t\tif (this.profiles.length === 0) return;\r\n\t\tconst next = this.selectedProviderIndex + delta;\r\n\t\tif (next < 0) {\r\n\t\t\tthis.selectedProviderIndex = this.profiles.length - 1;\r\n\t\t} else if (next >= this.profiles.length) {\r\n\t\t\tthis.selectedProviderIndex = 0;\r\n\t\t} else {\r\n\t\t\tthis.selectedProviderIndex = next;\r\n\t\t}\r\n\t\tthis.focusRegion = \"workspace\";\r\n\t\tthis.composer.focused = false;\r\n\t\tthis.animator.markFocusPulse();\r\n\t\tthis.ui.requestRender();\r\n\t}\r\n\r\n\tprivate renderMainPanel(width: number, height: number, frame: number, focusPulseActive: boolean, headerHeight: number): string[] {\r\n\t\tconst innerWidth = Math.max(1, width - 2);\r\n\t\tconst selection = this.profileService.getActiveSelection();\r\n\t\tconst activeProfile = selection.profileId ? this.profiles.find((item) => item.id === selection.profileId) : undefined;\r\n\t\tconst providerRows = renderProviderButtons(this.profiles, this.selectedProviderIndex, selection.profileId, innerWidth);\r\n\r\n\t\tconst body = [\r\n\t\t\tshellTheme.accent(\"Workspace\"),\r\n\t\t\tpadLine(\r\n\t\t\t\tactiveProfile\r\n\t\t\t\t\t? shellTheme.text(`Current provider: ${activeProfile.label} (${activeProfile.family})`)\r\n\t\t\t\t\t: shellTheme.warning(\"No active provider selected.\"),\r\n\t\t\t\tinnerWidth,\r\n\t\t\t),\r\n\t\t\tpadLine(\r\n\t\t\t\tselection.modelId ? shellTheme.text(`Current model: ${selection.modelId}`) : shellTheme.text(\"Current model: none\"),\r\n\t\t\t\tinnerWidth,\r\n\t\t\t),\r\n\t\t\tpadLine(shellTheme.muted(\"Provider entries below are the actual switch controls. Click a row or press Enter.\"), innerWidth),\r\n\t\t\t\"\",\r\n\t\t\tpadLine(shellTheme.accent(`Provider Controls ${shellTheme.accentSoft(`[${pulseDot(frame)}]`)}`), innerWidth),\r\n\t\t\t...providerRows.lines.map((line) => padLine(line, innerWidth)),\r\n\t\t\t\"\",\r\n\t\t\tpadLine(shellTheme.accent(\"Timeline\"), innerWidth),\r\n\t\t\t...(this.timeline.length > 0\r\n\t\t\t\t? this.timeline.slice(0, Math.max(1, height - 12)).map((line) => padLine(shellTheme.text(line), innerWidth))\r\n\t\t\t\t: [padLine(shellTheme.muted(\"No local dashboard activity yet. Use the composer below to populate this timeline.\"), innerWidth)]),\r\n\t\t];\r\n\r\n\t\tconst panelTopRow = headerHeight + 1;\r\n\t\tconst providerBaseRow = panelTopRow + 1 + 6;\r\n\t\tthis.providerRegions = providerRows.regions.map((region) => ({\r\n\t\t\t...region,\r\n\t\t\trow: providerBaseRow + region.row,\r\n\t\t\tcol: 2,\r\n\t\t}));\r\n\r\n\t\treturn framePanelFixed(\r\n\t\t\tthis.focusRegion === \"workspace\" ? \"Main Workspace [active]\" : \"Main Workspace\",\r\n\t\t\tbody,\r\n\t\t\twidth,\r\n\t\t\theight,\r\n\t\t\tgetPanelStyle(\"main\", this.focusRegion === \"workspace\", this.focusRegion === \"workspace\" && focusPulseActive),\r\n\t\t);\r\n\t}\r\n\r\n\tprivate renderStatusPanel(width: number, height: number, frame: number, focusPulseActive: boolean): string[] {\r\n\t\tconst innerWidth = Math.max(1, width - 2);\r\n\t\tconst selection = this.profileService.getActiveSelection();\r\n\t\tconst activeProfile = selection.profileId ? this.profiles.find((item) => item.id === selection.profileId) : undefined;\r\n\t\tconst body = [\r\n\t\t\tpadLine(shellTheme.accent(\"State\"), innerWidth),\r\n\t\t\tpadLine(shellTheme.success(`Task status: idle ${pulseDot(frame)}`), innerWidth),\r\n\t\t\tpadLine(shellTheme.text(\"Mode: solo\"), innerWidth),\r\n\t\t\t\"\",\r\n\t\t\tpadLine(shellTheme.accent(\"Context\"), innerWidth),\r\n\t\t\tpadLine(shellTheme.text(\"Usage: stub\"), innerWidth),\r\n\t\t\tpadLine(shellTheme.text(\"Window: stub\"), innerWidth),\r\n\t\t\t\"\",\r\n\t\t\tpadLine(shellTheme.accent(\"Todo\"), innerWidth),\r\n\t\t\tpadLine(shellTheme.text(\"1. Hook dashboard into real session history\"), innerWidth),\r\n\t\t\tpadLine(shellTheme.text(\"2. Replace local draft timeline with agent timeline\"), innerWidth),\r\n\t\t\tpadLine(shellTheme.text(\"3. Wire mode/model/session controls into dock dialogs\"), innerWidth),\r\n\t\t\t\"\",\r\n\t\t\tpadLine(shellTheme.accent(\"Selection\"), innerWidth),\r\n\t\t\tpadLine(shellTheme.text(`Provider: ${activeProfile?.label ?? \"none\"}`), innerWidth),\r\n\t\t\tpadLine(shellTheme.text(`Model: ${selection.modelId ?? \"none\"}`), innerWidth),\r\n\t\t];\r\n\r\n\t\treturn framePanelFixed(\"Status Panel\", body, width, height, getPanelStyle(\"status\", false, focusPulseActive));\r\n\t}\r\n\r\n\tprivate renderDock(width: number, height: number, focusPulseActive: boolean, bodyStartRow: number): string[] {\r\n\t\tconst innerWidth = Math.max(1, width - 2);\r\n\t\tconst selection = this.profileService.getActiveSelection();\r\n\t\tconst activeProfile = selection.profileId ? this.profiles.find((item) => item.id === selection.profileId) : undefined;\r\n\t\tconst actionChips = renderActionChips(\r\n\t\t\t[\r\n\t\t\t\t{ id: \"provider\", label: `Provider: ${activeProfile?.label ?? \"none\"}`, variant: \"accent\" },\r\n\t\t\t\t{ id: \"model\", label: `Model: ${selection.modelId ?? \"none\"}`, variant: \"muted\" },\r\n\t\t\t\t{ id: \"mode\", label: \"Mode: solo\", variant: \"muted\" },\r\n\t\t\t\t{ id: \"session\", label: \"Session\", variant: \"muted\" },\r\n\t\t\t\t{ id: \"focus\", label: \"Focus Composer\", variant: \"active\" },\r\n\t\t\t],\r\n\t\t\tinnerWidth,\r\n\t\t);\r\n\r\n\t\tconst composerLines = this.composer.render(innerWidth);\r\n\t\tconst actionBaseRow = bodyStartRow + 1;\r\n\t\tthis.actionRegions = actionChips.regions.map((region) => ({\r\n\t\t\t...region,\r\n\t\t\trow: actionBaseRow + region.row,\r\n\t\t\tcol: 2 + region.col,\r\n\t\t}));\r\n\r\n\t\tconst composerRowOffset = actionChips.lines.length + 2;\r\n\t\tthis.composerInputRegion = {\r\n\t\t\trow: bodyStartRow + 1 + composerRowOffset,\r\n\t\t\tcol: 2,\r\n\t\t\twidth: innerWidth,\r\n\t\t\theight: Math.max(1, composerLines.length),\r\n\t\t};\r\n\r\n\t\tconst body = [\r\n\t\t\t...actionChips.lines.map((line) => padLine(line, innerWidth)),\r\n\t\t\t\"\",\r\n\t\t\tpadLine(shellTheme.accent(\"Composer\"), innerWidth),\r\n\t\t\t...composerLines.map((line) => padLine(line, innerWidth)),\r\n\t\t\tpadLine(\r\n\t\t\t\tshellTheme.muted(\r\n\t\t\t\t\t`Focus ${getFocusLabel(this.focusRegion)} | Use the chips above as explicit controls`,\r\n\t\t\t\t),\r\n\t\t\t\tinnerWidth,\r\n\t\t\t),\r\n\t\t\tpadLine(\r\n\t\t\t\tshellTheme.muted(\r\n\t\t\t\t\t`Keys: ${shellKeymap.switchFocus} focus | ${shellKeymap.select} select/submit | ${shellKeymap.exit} exit`,\r\n\t\t\t\t),\r\n\t\t\t\tinnerWidth,\r\n\t\t\t),\r\n\t\t];\r\n\r\n\t\treturn framePanelFixed(\r\n\t\t\tthis.focusRegion === \"composer\" ? \"Bottom Dock [active]\" : \"Bottom Dock\",\r\n\t\t\tbody,\r\n\t\t\twidth,\r\n\t\t\theight,\r\n\t\t\tgetPanelStyle(\"dock\", this.focusRegion === \"composer\", this.focusRegion === \"composer\" && focusPulseActive),\r\n\t\t);\r\n\t}\r\n\r\n\tprivate activateProviderById(profileId: string): void {\r\n\t\tconst index = this.profiles.findIndex((item) => item.id === profileId);\r\n\t\tif (index === -1) return;\r\n\t\tthis.selectedProviderIndex = index;\r\n\t\tthis.switchActiveProfile(this.profiles[index]!);\r\n\t}\r\n\r\n\tprivate activateAction(actionId: string): void {\r\n\t\tswitch (actionId) {\r\n\t\t\tcase \"focus\":\r\n\t\t\t\tthis.focusRegion = \"composer\";\r\n\t\t\t\tthis.composer.focused = this._focused;\r\n\t\t\t\tthis.timeline.unshift(\"Composer focus selected from dock controls.\");\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"provider\":\r\n\t\t\t\tthis.focusRegion = \"workspace\";\r\n\t\t\t\tthis.composer.focused = false;\r\n\t\t\t\tthis.timeline.unshift(\"Provider control selected. Use provider rows to switch explicitly.\");\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"model\":\r\n\t\t\t\tthis.timeline.unshift(\"Model dialog placeholder selected. UI wiring comes next.\");\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"mode\":\r\n\t\t\t\tthis.timeline.unshift(\"Mode dialog placeholder selected. UI wiring comes next.\");\r\n\t\t\t\tbreak;\r\n\t\t\tcase \"session\":\r\n\t\t\t\tthis.timeline.unshift(\"Session control placeholder selected. UI wiring comes next.\");\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tthis.animator.markFocusPulse();\r\n\t\tthis.ui.requestRender();\r\n\t}\r\n\r\n\tprivate findHit(col: number, row: number, regions: GlobalClickableRegion[]): GlobalClickableRegion | undefined {\r\n\t\treturn regions.find((region) => this.pointInRect(col, row, region));\r\n\t}\r\n\r\n\tprivate hitAny(col: number, row: number, regions: GlobalClickableRegion[]): boolean {\r\n\t\treturn this.findHit(col, row, regions) !== undefined;\r\n\t}\r\n\r\n\tprivate pointInRect(col: number, row: number, rect: { col: number; row: number; width: number; height: number }): boolean {\r\n\t\treturn col >= rect.col && col < rect.col + rect.width && row >= rect.row && row < rect.row + rect.height;\r\n\t}\r\n\r\n\tprivate isPrimaryMouseActivation(event: ParsedMouseEvent): boolean {\r\n\t\treturn event.button === \"left\" && (event.action === \"press\" || event.action === \"release\");\r\n\t}\r\n\r\n\tprivate switchActiveProfile(profile: ProviderProfile): void {\r\n\t\tconst selection = this.profileService.getActiveSelection();\r\n\t\tconst nextModel = profile.models[0]?.id;\r\n\t\tconst isSameSelection = selection.profileId === profile.id && selection.modelId === nextModel;\r\n\r\n\t\tif (!isSameSelection) {\r\n\t\t\tthis.profileService.setActiveSelection(profile.id, nextModel);\r\n\t\t\tthis.timeline.unshift(`Active provider switched to ${profile.label}${nextModel ? ` (${nextModel})` : \"\"}`);\r\n\t\t}\r\n\r\n\t\tthis.animator.markFocusPulse();\r\n\t\tthis.ui.requestRender();\r\n\t}\r\n}\r\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["index.ts"],"sourcesContent":["export * from \"./dashboard-shell.js\";\r\nexport * from \"./clickables.js\";\r\nexport * from \"./keymap.js\";\r\nexport * from \"./mouse.js\";\r\nexport * from \"./run-shell.js\";\r\n"],"mappings":"AAAA,cAAc,sBAAsB;AACpC,cAAc,iBAAiB;AAC/B,cAAc,aAAa;AAC3B,cAAc,YAAY;AAC1B,cAAc,gBAAgB","ignoreList":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const shellKeymap = {
|
|
2
|
+
switchFocus: "Tab",
|
|
3
|
+
select: "Enter",
|
|
4
|
+
navigate: "Up/Down",
|
|
5
|
+
exit: "Esc or Ctrl+C"
|
|
6
|
+
};
|
|
7
|
+
export function getFocusLabel(region) {
|
|
8
|
+
switch (region) {
|
|
9
|
+
case "workspace":
|
|
10
|
+
return "Workspace";
|
|
11
|
+
case "composer":
|
|
12
|
+
return "Composer";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["shellKeymap","switchFocus","select","navigate","exit","getFocusLabel","region"],"sources":["keymap.ts"],"sourcesContent":["export type ShellFocusRegion = \"workspace\" | \"composer\";\r\n\r\nexport const shellKeymap = {\r\n\tswitchFocus: \"Tab\",\r\n\tselect: \"Enter\",\r\n\tnavigate: \"Up/Down\",\r\n\texit: \"Esc or Ctrl+C\",\r\n};\r\n\r\nexport function getFocusLabel(region: ShellFocusRegion): string {\r\n\tswitch (region) {\r\n\t\tcase \"workspace\":\r\n\t\t\treturn \"Workspace\";\r\n\t\tcase \"composer\":\r\n\t\t\treturn \"Composer\";\r\n\t}\r\n}\r\n"],"mappings":"AAEA,OAAO,MAAMA,WAAW,GAAG;EAC1BC,WAAW,EAAE,KAAK;EAClBC,MAAM,EAAE,OAAO;EACfC,QAAQ,EAAE,SAAS;EACnBC,IAAI,EAAE;AACP,CAAC;AAED,OAAO,SAASC,aAAaA,CAACC,MAAwB,EAAU;EAC/D,QAAQA,MAAM;IACb,KAAK,WAAW;MACf,OAAO,WAAW;IACnB,KAAK,UAAU;MACd,OAAO,UAAU;EACnB;AACD","ignoreList":[]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const SGR_MOUSE_PATTERN = /^\x1b\[<(\d+);(\d+);(\d+)([Mm])$/;
|
|
2
|
+
export const ENABLE_MOUSE_SEQUENCE = "\x1b[?1000h\x1b[?1006h";
|
|
3
|
+
export const DISABLE_MOUSE_SEQUENCE = "\x1b[?1000l\x1b[?1006l";
|
|
4
|
+
export function parseMouseSequence(data) {
|
|
5
|
+
const match = data.match(SGR_MOUSE_PATTERN);
|
|
6
|
+
if (!match) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const code = Number(match[1]);
|
|
10
|
+
const col = Number(match[2]);
|
|
11
|
+
const row = Number(match[3]);
|
|
12
|
+
const terminator = match[4];
|
|
13
|
+
const shift = (code & 4) !== 0;
|
|
14
|
+
const alt = (code & 8) !== 0;
|
|
15
|
+
const ctrl = (code & 16) !== 0;
|
|
16
|
+
const motion = (code & 32) !== 0;
|
|
17
|
+
const wheel = (code & 64) !== 0;
|
|
18
|
+
const baseButton = code & 3;
|
|
19
|
+
if (wheel) {
|
|
20
|
+
return {
|
|
21
|
+
button: baseButton === 0 ? "wheel-up" : baseButton === 1 ? "wheel-down" : "unknown",
|
|
22
|
+
action: "scroll",
|
|
23
|
+
row,
|
|
24
|
+
col,
|
|
25
|
+
shift,
|
|
26
|
+
alt,
|
|
27
|
+
ctrl
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
button: baseButton === 0 ? "left" : baseButton === 1 ? "middle" : baseButton === 2 ? "right" : "unknown",
|
|
32
|
+
action: motion ? terminator === "M" ? "drag" : "move" : terminator === "M" ? "press" : "release",
|
|
33
|
+
row,
|
|
34
|
+
col,
|
|
35
|
+
shift,
|
|
36
|
+
alt,
|
|
37
|
+
ctrl
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["SGR_MOUSE_PATTERN","ENABLE_MOUSE_SEQUENCE","DISABLE_MOUSE_SEQUENCE","parseMouseSequence","data","match","code","Number","col","row","terminator","shift","alt","ctrl","motion","wheel","baseButton","button","action"],"sources":["mouse.ts"],"sourcesContent":["export type MouseButton = \"left\" | \"middle\" | \"right\" | \"wheel-up\" | \"wheel-down\" | \"unknown\";\r\nexport type MouseAction = \"press\" | \"release\" | \"drag\" | \"move\" | \"scroll\";\r\n\r\nexport interface ParsedMouseEvent {\r\n\tbutton: MouseButton;\r\n\taction: MouseAction;\r\n\trow: number;\r\n\tcol: number;\r\n\tshift: boolean;\r\n\talt: boolean;\r\n\tctrl: boolean;\r\n}\r\n\r\nconst SGR_MOUSE_PATTERN = /^\\x1b\\[<(\\d+);(\\d+);(\\d+)([Mm])$/;\r\n\r\nexport const ENABLE_MOUSE_SEQUENCE = \"\\x1b[?1000h\\x1b[?1006h\";\r\nexport const DISABLE_MOUSE_SEQUENCE = \"\\x1b[?1000l\\x1b[?1006l\";\r\n\r\nexport function parseMouseSequence(data: string): ParsedMouseEvent | null {\r\n\tconst match = data.match(SGR_MOUSE_PATTERN);\r\n\tif (!match) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tconst code = Number(match[1]);\r\n\tconst col = Number(match[2]);\r\n\tconst row = Number(match[3]);\r\n\tconst terminator = match[4];\r\n\r\n\tconst shift = (code & 4) !== 0;\r\n\tconst alt = (code & 8) !== 0;\r\n\tconst ctrl = (code & 16) !== 0;\r\n\tconst motion = (code & 32) !== 0;\r\n\tconst wheel = (code & 64) !== 0;\r\n\tconst baseButton = code & 3;\r\n\r\n\tif (wheel) {\r\n\t\treturn {\r\n\t\t\tbutton: baseButton === 0 ? \"wheel-up\" : baseButton === 1 ? \"wheel-down\" : \"unknown\",\r\n\t\t\taction: \"scroll\",\r\n\t\t\trow,\r\n\t\t\tcol,\r\n\t\t\tshift,\r\n\t\t\talt,\r\n\t\t\tctrl,\r\n\t\t};\r\n\t}\r\n\r\n\treturn {\r\n\t\tbutton: baseButton === 0 ? \"left\" : baseButton === 1 ? \"middle\" : baseButton === 2 ? \"right\" : \"unknown\",\r\n\t\taction: motion ? (terminator === \"M\" ? \"drag\" : \"move\") : terminator === \"M\" ? \"press\" : \"release\",\r\n\t\trow,\r\n\t\tcol,\r\n\t\tshift,\r\n\t\talt,\r\n\t\tctrl,\r\n\t};\r\n}\r\n"],"mappings":"AAaA,MAAMA,iBAAiB,GAAG,kCAAkC;AAE5D,OAAO,MAAMC,qBAAqB,GAAG,wBAAwB;AAC7D,OAAO,MAAMC,sBAAsB,GAAG,wBAAwB;AAE9D,OAAO,SAASC,kBAAkBA,CAACC,IAAY,EAA2B;EACzE,MAAMC,KAAK,GAAGD,IAAI,CAACC,KAAK,CAACL,iBAAiB,CAAC;EAC3C,IAAI,CAACK,KAAK,EAAE;IACX,OAAO,IAAI;EACZ;EAEA,MAAMC,IAAI,GAAGC,MAAM,CAACF,KAAK,CAAC,CAAC,CAAC,CAAC;EAC7B,MAAMG,GAAG,GAAGD,MAAM,CAACF,KAAK,CAAC,CAAC,CAAC,CAAC;EAC5B,MAAMI,GAAG,GAAGF,MAAM,CAACF,KAAK,CAAC,CAAC,CAAC,CAAC;EAC5B,MAAMK,UAAU,GAAGL,KAAK,CAAC,CAAC,CAAC;EAE3B,MAAMM,KAAK,GAAG,CAACL,IAAI,GAAG,CAAC,MAAM,CAAC;EAC9B,MAAMM,GAAG,GAAG,CAACN,IAAI,GAAG,CAAC,MAAM,CAAC;EAC5B,MAAMO,IAAI,GAAG,CAACP,IAAI,GAAG,EAAE,MAAM,CAAC;EAC9B,MAAMQ,MAAM,GAAG,CAACR,IAAI,GAAG,EAAE,MAAM,CAAC;EAChC,MAAMS,KAAK,GAAG,CAACT,IAAI,GAAG,EAAE,MAAM,CAAC;EAC/B,MAAMU,UAAU,GAAGV,IAAI,GAAG,CAAC;EAE3B,IAAIS,KAAK,EAAE;IACV,OAAO;MACNE,MAAM,EAAED,UAAU,KAAK,CAAC,GAAG,UAAU,GAAGA,UAAU,KAAK,CAAC,GAAG,YAAY,GAAG,SAAS;MACnFE,MAAM,EAAE,QAAQ;MAChBT,GAAG;MACHD,GAAG;MACHG,KAAK;MACLC,GAAG;MACHC;IACD,CAAC;EACF;EAEA,OAAO;IACNI,MAAM,EAAED,UAAU,KAAK,CAAC,GAAG,MAAM,GAAGA,UAAU,KAAK,CAAC,GAAG,QAAQ,GAAGA,UAAU,KAAK,CAAC,GAAG,OAAO,GAAG,SAAS;IACxGE,MAAM,EAAEJ,MAAM,GAAIJ,UAAU,KAAK,GAAG,GAAG,MAAM,GAAG,MAAM,GAAIA,UAAU,KAAK,GAAG,GAAG,OAAO,GAAG,SAAS;IAClGD,GAAG;IACHD,GAAG;IACHG,KAAK;IACLC,GAAG;IACHC;EACD,CAAC;AACF","ignoreList":[]}
|