auq-mcp-server 2.6.4 → 2.7.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 +56 -2
- package/dist/bin/auq.js +36 -3
- package/dist/bin/tui-app.js +27 -6
- package/dist/package.json +7 -2
- package/dist/src/__tests__/schema-validation.test.js +61 -1
- package/dist/src/cli/commands/__tests__/fetch-answers.test.js +310 -0
- package/dist/src/cli/commands/__tests__/history.test.js +211 -0
- package/dist/src/cli/commands/answer.js +11 -0
- package/dist/src/cli/commands/config.js +48 -0
- package/dist/src/cli/commands/fetch-answers.js +205 -0
- package/dist/src/cli/commands/history.js +375 -0
- package/dist/src/config/__tests__/ConfigLoader.test.js +38 -0
- package/dist/src/config/defaults.js +1 -0
- package/dist/src/config/types.js +1 -0
- package/dist/src/core/ask-user-questions.js +63 -0
- package/dist/src/i18n/locales/en.js +2 -2
- package/dist/src/server.js +59 -2
- package/dist/src/session/ResponseFormatter.js +79 -2
- package/dist/src/session/SessionManager.js +36 -0
- package/dist/src/session/__tests__/ResponseFormatter.test.js +86 -0
- package/dist/src/session/__tests__/SessionManager.test.js +129 -0
- package/dist/src/shared/schemas.js +8 -0
- package/dist/src/tui/ThemeProvider.js +3 -3
- package/dist/src/tui/components/Header.js +2 -1
- package/dist/src/tui/components/OptionsList.js +1 -1
- package/dist/src/tui/components/SessionPicker.js +1 -1
- package/dist/src/tui/components/StepperView.js +1 -1
- package/dist/src/tui/components/__tests__/ConfirmationDialog.test.js +1 -1
- package/dist/src/tui/components/__tests__/Footer.test.js +1 -1
- package/dist/src/tui/components/__tests__/MarkdownPrompt.test.js +1 -1
- package/dist/src/tui/components/__tests__/ReviewScreen.test.js +1 -1
- package/dist/src/tui/components/__tests__/SessionDots.test.js +1 -1
- package/dist/src/tui/components/__tests__/SessionPicker.test.js +1 -1
- package/dist/src/tui/components/__tests__/StepperView.abandoned.test.js +1 -1
- package/dist/src/tui/components/__tests__/StepperView.keyboard.test.js +1 -1
- package/dist/src/tui/components/__tests__/StepperView.state.test.js +1 -1
- package/dist/src/tui/components/__tests__/WaitingScreen.test.js +1 -1
- package/dist/src/tui/shared/session-events.js +4 -0
- package/dist/src/tui/shared/themes/catppuccin-latte.js +130 -0
- package/dist/src/tui/shared/themes/catppuccin-mocha.js +131 -0
- package/dist/src/tui/shared/themes/dark.js +131 -0
- package/dist/src/tui/shared/themes/dracula.js +131 -0
- package/dist/src/tui/shared/themes/github-dark.js +129 -0
- package/dist/src/tui/shared/themes/github-light.js +129 -0
- package/dist/src/tui/shared/themes/gruvbox-dark.js +130 -0
- package/dist/src/tui/shared/themes/gruvbox-light.js +130 -0
- package/dist/src/tui/shared/themes/index.js +70 -0
- package/dist/src/tui/shared/themes/light.js +130 -0
- package/dist/src/tui/shared/themes/loader.js +111 -0
- package/dist/src/tui/shared/themes/monokai.js +132 -0
- package/dist/src/tui/shared/themes/nord.js +130 -0
- package/dist/src/tui/shared/themes/one-dark.js +131 -0
- package/dist/src/tui/shared/themes/rose-pine.js +131 -0
- package/dist/src/tui/shared/themes/solarized-dark.js +130 -0
- package/dist/src/tui/shared/themes/solarized-light.js +130 -0
- package/dist/src/tui/shared/themes/tokyo-night.js +131 -0
- package/dist/src/tui/shared/themes/types.js +1 -0
- package/dist/src/tui/shared/types.js +1 -0
- package/dist/src/tui/shared/utils/config.js +80 -0
- package/dist/src/tui/shared/utils/detectTheme.js +33 -0
- package/dist/src/tui/shared/utils/index.js +6 -0
- package/dist/src/tui/shared/utils/recommended.js +52 -0
- package/dist/src/tui/shared/utils/relativeTime.js +24 -0
- package/dist/src/tui/shared/utils/sessionSwitching.js +56 -0
- package/dist/src/tui/shared/utils/staleDetection.js +51 -0
- package/dist/src/tui/themes/catppuccin-latte.js +2 -127
- package/dist/src/tui/themes/catppuccin-mocha.js +2 -127
- package/dist/src/tui/themes/dark.js +2 -128
- package/dist/src/tui/themes/dracula.js +2 -127
- package/dist/src/tui/themes/github-dark.js +2 -126
- package/dist/src/tui/themes/github-light.js +2 -126
- package/dist/src/tui/themes/gruvbox-dark.js +2 -127
- package/dist/src/tui/themes/gruvbox-light.js +2 -127
- package/dist/src/tui/themes/index.js +2 -70
- package/dist/src/tui/themes/light.js +2 -127
- package/dist/src/tui/themes/loader.js +2 -111
- package/dist/src/tui/themes/monokai.js +2 -128
- package/dist/src/tui/themes/nord.js +2 -127
- package/dist/src/tui/themes/one-dark.js +2 -127
- package/dist/src/tui/themes/rose-pine.js +2 -128
- package/dist/src/tui/themes/solarized-dark.js +2 -127
- package/dist/src/tui/themes/solarized-light.js +2 -127
- package/dist/src/tui/themes/tokyo-night.js +2 -127
- package/dist/src/tui/themes/types.js +2 -1
- package/dist/src/tui/types.js +1 -1
- package/dist/src/tui/utils/__tests__/recommended.test.js +1 -1
- package/dist/src/tui/utils/__tests__/relativeTime.test.js +1 -1
- package/dist/src/tui/utils/__tests__/sessionSwitching.test.js +1 -1
- package/dist/src/tui/utils/__tests__/staleDetection.test.js +1 -1
- package/dist/src/tui/utils/config.js +1 -80
- package/dist/src/tui/utils/detectTheme.js +1 -22
- package/dist/src/tui/utils/recommended.js +1 -52
- package/dist/src/tui/utils/relativeTime.js +1 -24
- package/dist/src/tui/utils/sessionSwitching.js +1 -56
- package/dist/src/tui/utils/staleDetection.js +1 -51
- package/package.json +7 -2
|
@@ -1,127 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
* Precision colors for machines and people.
|
|
4
|
-
* https://ethanschoonover.com/solarized/
|
|
5
|
-
*/
|
|
6
|
-
export const solarizedDarkTheme = {
|
|
7
|
-
name: "solarized-dark",
|
|
8
|
-
gradient: {
|
|
9
|
-
start: "#268bd2", // blue
|
|
10
|
-
middle: "#2aa198", // cyan
|
|
11
|
-
end: "#268bd2",
|
|
12
|
-
},
|
|
13
|
-
colors: {
|
|
14
|
-
primary: "#268bd2", // blue
|
|
15
|
-
success: "#859900", // green
|
|
16
|
-
warning: "#b58900", // yellow
|
|
17
|
-
error: "#dc322f", // red
|
|
18
|
-
info: "#2aa198", // cyan
|
|
19
|
-
focused: "#268bd2",
|
|
20
|
-
selected: "#859900",
|
|
21
|
-
pending: "#b58900",
|
|
22
|
-
unansweredHighlight: "#dc322f",
|
|
23
|
-
text: "#839496", // base0
|
|
24
|
-
textDim: "#6c7c83", // base01 brightened
|
|
25
|
-
textBold: "#93a1a1", // base1
|
|
26
|
-
},
|
|
27
|
-
borders: {
|
|
28
|
-
primary: "#268bd2",
|
|
29
|
-
warning: "#b58900",
|
|
30
|
-
error: "#dc322f",
|
|
31
|
-
neutral: "#073642", // base02
|
|
32
|
-
},
|
|
33
|
-
components: {
|
|
34
|
-
header: {
|
|
35
|
-
border: "#586e75", // base01 - slightly more visible
|
|
36
|
-
queueActive: "#268bd2",
|
|
37
|
-
queueEmpty: "#6c7c83",
|
|
38
|
-
queueFlash: "#2aa198",
|
|
39
|
-
pillBg: "#073642",
|
|
40
|
-
},
|
|
41
|
-
directory: {
|
|
42
|
-
label: "#6c7c83",
|
|
43
|
-
path: "#839496",
|
|
44
|
-
},
|
|
45
|
-
tabBar: {
|
|
46
|
-
selected: "#93a1a1",
|
|
47
|
-
selectedBg: "#073642",
|
|
48
|
-
default: "#6c7c83",
|
|
49
|
-
answered: "#859900",
|
|
50
|
-
unanswered: "#6c7c83",
|
|
51
|
-
divider: "#073642",
|
|
52
|
-
},
|
|
53
|
-
options: {
|
|
54
|
-
focused: "#859900",
|
|
55
|
-
focusedBg: "#073642",
|
|
56
|
-
selected: "#268bd2",
|
|
57
|
-
selectedBg: "#073642",
|
|
58
|
-
default: "#839496",
|
|
59
|
-
description: "#93a1a1", // base1 - lighter for readability
|
|
60
|
-
hint: "#93a1a1", // base1 - lighter for readability
|
|
61
|
-
},
|
|
62
|
-
input: {
|
|
63
|
-
border: "#073642",
|
|
64
|
-
borderFocused: "#268bd2",
|
|
65
|
-
placeholder: "#6c7c83",
|
|
66
|
-
cursor: "#268bd2",
|
|
67
|
-
cursorDim: "#2aa198",
|
|
68
|
-
},
|
|
69
|
-
review: {
|
|
70
|
-
border: "#073642",
|
|
71
|
-
confirmBorder: "#268bd2",
|
|
72
|
-
selectedOption: "#859900",
|
|
73
|
-
customAnswer: "#b58900",
|
|
74
|
-
questionId: "#6c7c83",
|
|
75
|
-
divider: "#073642",
|
|
76
|
-
},
|
|
77
|
-
questionDisplay: {
|
|
78
|
-
questionId: "#268bd2",
|
|
79
|
-
typeIndicator: "#6c7c83",
|
|
80
|
-
elapsed: "#6c7c83",
|
|
81
|
-
},
|
|
82
|
-
footer: {
|
|
83
|
-
border: "#073642",
|
|
84
|
-
keyBg: "#073642",
|
|
85
|
-
keyFg: "#268bd2",
|
|
86
|
-
action: "#839496", // base0 - brighter for visibility
|
|
87
|
-
separator: "#073642",
|
|
88
|
-
},
|
|
89
|
-
toast: {
|
|
90
|
-
success: "#859900",
|
|
91
|
-
successPillBg: "#073642",
|
|
92
|
-
error: "#dc322f",
|
|
93
|
-
info: "#268bd2",
|
|
94
|
-
warning: "#b58900",
|
|
95
|
-
border: "#073642",
|
|
96
|
-
},
|
|
97
|
-
markdown: {
|
|
98
|
-
codeBlockBg: "#002b36",
|
|
99
|
-
codeBlockText: "#839496",
|
|
100
|
-
codeBlockBorder: "#073642",
|
|
101
|
-
},
|
|
102
|
-
sessionDots: {
|
|
103
|
-
active: "#268bd2",
|
|
104
|
-
answered: "#859900",
|
|
105
|
-
inProgress: "#b58900",
|
|
106
|
-
untouched: "#6c7c83",
|
|
107
|
-
number: "#839496",
|
|
108
|
-
activeNumber: "#268bd2",
|
|
109
|
-
stale: "#b58900",
|
|
110
|
-
abandoned: "#dc322f",
|
|
111
|
-
},
|
|
112
|
-
sessionPicker: {
|
|
113
|
-
border: "#268bd2",
|
|
114
|
-
title: "#268bd2",
|
|
115
|
-
rowText: "#839496",
|
|
116
|
-
rowDim: "#6c7c83",
|
|
117
|
-
highlightBg: "#073642",
|
|
118
|
-
highlightFg: "#859900",
|
|
119
|
-
activeMark: "#268bd2",
|
|
120
|
-
progress: "#2aa198",
|
|
121
|
-
staleIcon: "#b58900",
|
|
122
|
-
staleText: "#b58900",
|
|
123
|
-
staleAge: "#b58900",
|
|
124
|
-
staleSubtitle: "#6c7c83",
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
};
|
|
1
|
+
// Re-export from shared location for backward compatibility
|
|
2
|
+
export * from "../shared/themes/solarized-dark.js";
|
|
@@ -1,127 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
* Precision colors for machines and people - light variant.
|
|
4
|
-
* https://ethanschoonover.com/solarized/
|
|
5
|
-
*/
|
|
6
|
-
export const solarizedLightTheme = {
|
|
7
|
-
name: "solarized-light",
|
|
8
|
-
gradient: {
|
|
9
|
-
start: "#268bd2", // blue
|
|
10
|
-
middle: "#2aa198", // cyan
|
|
11
|
-
end: "#268bd2",
|
|
12
|
-
},
|
|
13
|
-
colors: {
|
|
14
|
-
primary: "#268bd2", // blue
|
|
15
|
-
success: "#859900", // green
|
|
16
|
-
warning: "#b58900", // yellow
|
|
17
|
-
error: "#dc322f", // red
|
|
18
|
-
info: "#2aa198", // cyan
|
|
19
|
-
focused: "#268bd2",
|
|
20
|
-
selected: "#859900",
|
|
21
|
-
pending: "#b58900",
|
|
22
|
-
unansweredHighlight: "#dc322f",
|
|
23
|
-
text: "#657b83", // base00
|
|
24
|
-
textDim: "#a3b1b1", // base1 lightened
|
|
25
|
-
textBold: "#586e75", // base01
|
|
26
|
-
},
|
|
27
|
-
borders: {
|
|
28
|
-
primary: "#268bd2",
|
|
29
|
-
warning: "#b58900",
|
|
30
|
-
error: "#dc322f",
|
|
31
|
-
neutral: "#eee8d5", // base2
|
|
32
|
-
},
|
|
33
|
-
components: {
|
|
34
|
-
header: {
|
|
35
|
-
border: "#93a1a1", // base1 - slightly more visible
|
|
36
|
-
queueActive: "#268bd2",
|
|
37
|
-
queueEmpty: "#a3b1b1",
|
|
38
|
-
queueFlash: "#2aa198",
|
|
39
|
-
pillBg: "#eee8d5",
|
|
40
|
-
},
|
|
41
|
-
directory: {
|
|
42
|
-
label: "#a3b1b1",
|
|
43
|
-
path: "#657b83",
|
|
44
|
-
},
|
|
45
|
-
tabBar: {
|
|
46
|
-
selected: "#586e75",
|
|
47
|
-
selectedBg: "#eee8d5",
|
|
48
|
-
default: "#a3b1b1",
|
|
49
|
-
answered: "#859900",
|
|
50
|
-
unanswered: "#a3b1b1",
|
|
51
|
-
divider: "#eee8d5",
|
|
52
|
-
},
|
|
53
|
-
options: {
|
|
54
|
-
focused: "#859900",
|
|
55
|
-
focusedBg: "#eee8d5",
|
|
56
|
-
selected: "#268bd2",
|
|
57
|
-
selectedBg: "#eee8d5",
|
|
58
|
-
default: "#657b83",
|
|
59
|
-
description: "#586e75", // base01 - darker for readability
|
|
60
|
-
hint: "#586e75", // base01 - darker for readability
|
|
61
|
-
},
|
|
62
|
-
input: {
|
|
63
|
-
border: "#eee8d5",
|
|
64
|
-
borderFocused: "#268bd2",
|
|
65
|
-
placeholder: "#a3b1b1",
|
|
66
|
-
cursor: "#268bd2",
|
|
67
|
-
cursorDim: "#2aa198",
|
|
68
|
-
},
|
|
69
|
-
review: {
|
|
70
|
-
border: "#eee8d5",
|
|
71
|
-
confirmBorder: "#268bd2",
|
|
72
|
-
selectedOption: "#859900",
|
|
73
|
-
customAnswer: "#b58900",
|
|
74
|
-
questionId: "#a3b1b1",
|
|
75
|
-
divider: "#eee8d5",
|
|
76
|
-
},
|
|
77
|
-
questionDisplay: {
|
|
78
|
-
questionId: "#268bd2",
|
|
79
|
-
typeIndicator: "#a3b1b1",
|
|
80
|
-
elapsed: "#a3b1b1",
|
|
81
|
-
},
|
|
82
|
-
footer: {
|
|
83
|
-
border: "#eee8d5",
|
|
84
|
-
keyBg: "#eee8d5",
|
|
85
|
-
keyFg: "#268bd2",
|
|
86
|
-
action: "#657b83", // base00 - darker for visibility
|
|
87
|
-
separator: "#eee8d5",
|
|
88
|
-
},
|
|
89
|
-
toast: {
|
|
90
|
-
success: "#859900",
|
|
91
|
-
successPillBg: "#eee8d5",
|
|
92
|
-
error: "#dc322f",
|
|
93
|
-
info: "#268bd2",
|
|
94
|
-
warning: "#b58900",
|
|
95
|
-
border: "#eee8d5",
|
|
96
|
-
},
|
|
97
|
-
markdown: {
|
|
98
|
-
codeBlockBg: "#fdf6e3",
|
|
99
|
-
codeBlockText: "#657b83",
|
|
100
|
-
codeBlockBorder: "#eee8d5",
|
|
101
|
-
},
|
|
102
|
-
sessionDots: {
|
|
103
|
-
active: "#268bd2",
|
|
104
|
-
answered: "#859900",
|
|
105
|
-
inProgress: "#b58900",
|
|
106
|
-
untouched: "#a3b1b1",
|
|
107
|
-
number: "#657b83",
|
|
108
|
-
activeNumber: "#268bd2",
|
|
109
|
-
stale: "#b58900",
|
|
110
|
-
abandoned: "#dc322f",
|
|
111
|
-
},
|
|
112
|
-
sessionPicker: {
|
|
113
|
-
border: "#268bd2",
|
|
114
|
-
title: "#268bd2",
|
|
115
|
-
rowText: "#657b83",
|
|
116
|
-
rowDim: "#a3b1b1",
|
|
117
|
-
highlightBg: "#eee8d5",
|
|
118
|
-
highlightFg: "#859900",
|
|
119
|
-
activeMark: "#268bd2",
|
|
120
|
-
progress: "#2aa198",
|
|
121
|
-
staleIcon: "#b58900",
|
|
122
|
-
staleText: "#b58900",
|
|
123
|
-
staleAge: "#b58900",
|
|
124
|
-
staleSubtitle: "#a3b1b1",
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
};
|
|
1
|
+
// Re-export from shared location for backward compatibility
|
|
2
|
+
export * from "../shared/themes/solarized-light.js";
|
|
@@ -1,127 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
* A clean, dark theme celebrating the lights of downtown Tokyo.
|
|
4
|
-
* https://github.com/enkia/tokyo-night-vscode-theme
|
|
5
|
-
*/
|
|
6
|
-
export const tokyoNightTheme = {
|
|
7
|
-
name: "tokyo-night",
|
|
8
|
-
gradient: {
|
|
9
|
-
start: "#7aa2f7", // blue
|
|
10
|
-
middle: "#7dcfff", // cyan
|
|
11
|
-
end: "#7aa2f7",
|
|
12
|
-
},
|
|
13
|
-
colors: {
|
|
14
|
-
primary: "#7aa2f7", // blue
|
|
15
|
-
success: "#9ece6a", // green
|
|
16
|
-
warning: "#e0af68", // yellow
|
|
17
|
-
error: "#f7768e", // red
|
|
18
|
-
info: "#7dcfff", // cyan
|
|
19
|
-
focused: "#7aa2f7",
|
|
20
|
-
selected: "#9ece6a",
|
|
21
|
-
pending: "#e0af68",
|
|
22
|
-
unansweredHighlight: "#f7768e",
|
|
23
|
-
text: "#c0caf5", // foreground
|
|
24
|
-
textDim: "#7078A3", // comment brightened
|
|
25
|
-
textBold: "#c0caf5",
|
|
26
|
-
},
|
|
27
|
-
borders: {
|
|
28
|
-
primary: "#7aa2f7",
|
|
29
|
-
warning: "#e0af68",
|
|
30
|
-
error: "#f7768e",
|
|
31
|
-
neutral: "#24283b", // storm bg
|
|
32
|
-
},
|
|
33
|
-
components: {
|
|
34
|
-
header: {
|
|
35
|
-
border: "#3b4261", // slightly more visible
|
|
36
|
-
queueActive: "#7aa2f7",
|
|
37
|
-
queueEmpty: "#7078A3",
|
|
38
|
-
queueFlash: "#7dcfff",
|
|
39
|
-
pillBg: "#24283b",
|
|
40
|
-
},
|
|
41
|
-
directory: {
|
|
42
|
-
label: "#7078A3",
|
|
43
|
-
path: "#c0caf5",
|
|
44
|
-
},
|
|
45
|
-
tabBar: {
|
|
46
|
-
selected: "#c0caf5",
|
|
47
|
-
selectedBg: "#24283b",
|
|
48
|
-
default: "#7078A3",
|
|
49
|
-
answered: "#9ece6a",
|
|
50
|
-
unanswered: "#7078A3",
|
|
51
|
-
divider: "#24283b",
|
|
52
|
-
},
|
|
53
|
-
options: {
|
|
54
|
-
focused: "#9ece6a",
|
|
55
|
-
focusedBg: "#24283b",
|
|
56
|
-
selected: "#7aa2f7",
|
|
57
|
-
selectedBg: "#24283b",
|
|
58
|
-
default: "#c0caf5",
|
|
59
|
-
description: "#9aa5ce", // lighter for readability
|
|
60
|
-
hint: "#9aa5ce", // lighter for readability
|
|
61
|
-
},
|
|
62
|
-
input: {
|
|
63
|
-
border: "#24283b",
|
|
64
|
-
borderFocused: "#7aa2f7",
|
|
65
|
-
placeholder: "#7078A3",
|
|
66
|
-
cursor: "#7aa2f7",
|
|
67
|
-
cursorDim: "#7dcfff",
|
|
68
|
-
},
|
|
69
|
-
review: {
|
|
70
|
-
border: "#24283b",
|
|
71
|
-
confirmBorder: "#7aa2f7",
|
|
72
|
-
selectedOption: "#9ece6a",
|
|
73
|
-
customAnswer: "#e0af68",
|
|
74
|
-
questionId: "#7078A3",
|
|
75
|
-
divider: "#24283b",
|
|
76
|
-
},
|
|
77
|
-
questionDisplay: {
|
|
78
|
-
questionId: "#7aa2f7",
|
|
79
|
-
typeIndicator: "#7078A3",
|
|
80
|
-
elapsed: "#7078A3",
|
|
81
|
-
},
|
|
82
|
-
footer: {
|
|
83
|
-
border: "#24283b",
|
|
84
|
-
keyBg: "#24283b",
|
|
85
|
-
keyFg: "#7aa2f7",
|
|
86
|
-
action: "#7B88A1",
|
|
87
|
-
separator: "#24283b",
|
|
88
|
-
},
|
|
89
|
-
toast: {
|
|
90
|
-
success: "#9ece6a",
|
|
91
|
-
successPillBg: "#1a1b26",
|
|
92
|
-
error: "#f7768e",
|
|
93
|
-
info: "#7aa2f7",
|
|
94
|
-
warning: "#e0af68",
|
|
95
|
-
border: "#24283b",
|
|
96
|
-
},
|
|
97
|
-
markdown: {
|
|
98
|
-
codeBlockBg: "#1a1b26",
|
|
99
|
-
codeBlockText: "#c0caf5",
|
|
100
|
-
codeBlockBorder: "#24283b",
|
|
101
|
-
},
|
|
102
|
-
sessionDots: {
|
|
103
|
-
active: "#7aa2f7",
|
|
104
|
-
answered: "#9ece6a",
|
|
105
|
-
inProgress: "#e0af68",
|
|
106
|
-
untouched: "#7078A3",
|
|
107
|
-
number: "#c0caf5",
|
|
108
|
-
activeNumber: "#7aa2f7",
|
|
109
|
-
stale: "#e0af68",
|
|
110
|
-
abandoned: "#f7768e",
|
|
111
|
-
},
|
|
112
|
-
sessionPicker: {
|
|
113
|
-
border: "#7aa2f7",
|
|
114
|
-
title: "#7aa2f7",
|
|
115
|
-
rowText: "#c0caf5",
|
|
116
|
-
rowDim: "#7078A3",
|
|
117
|
-
highlightBg: "#24283b",
|
|
118
|
-
highlightFg: "#9ece6a",
|
|
119
|
-
activeMark: "#7aa2f7",
|
|
120
|
-
progress: "#7dcfff",
|
|
121
|
-
staleIcon: "#e0af68",
|
|
122
|
-
staleText: "#e0af68",
|
|
123
|
-
staleAge: "#e0af68",
|
|
124
|
-
staleSubtitle: "#7078A3",
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
};
|
|
1
|
+
// Re-export from shared location for backward compatibility
|
|
2
|
+
export * from "../shared/themes/tokyo-night.js";
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
// Re-export from shared location for backward compatibility
|
|
2
|
+
export * from "../shared/themes/types.js";
|
package/dist/src/tui/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from "./shared/types.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { isRecommendedOption, extractCleanLabel, RECOMMENDED_PATTERNS, } from "
|
|
2
|
+
import { isRecommendedOption, extractCleanLabel, RECOMMENDED_PATTERNS, } from "../../shared/utils/recommended.js";
|
|
3
3
|
describe("isRecommendedOption", () => {
|
|
4
4
|
describe("English patterns", () => {
|
|
5
5
|
it("should detect (recommended) at end of label", () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { formatRelativeTime } from "
|
|
2
|
+
import { formatRelativeTime } from "../../shared/utils/relativeTime.js";
|
|
3
3
|
describe("formatRelativeTime", () => {
|
|
4
4
|
const now = new Date("2026-01-01T00:00:00.000Z");
|
|
5
5
|
beforeEach(() => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { getAdjustedIndexAfterRemoval, getDirectJumpIndex, getNextSessionIndex, getPrevSessionIndex, } from "
|
|
2
|
+
import { getAdjustedIndexAfterRemoval, getDirectJumpIndex, getNextSessionIndex, getPrevSessionIndex, } from "../../shared/utils/sessionSwitching.js";
|
|
3
3
|
describe("getNextSessionIndex", () => {
|
|
4
4
|
it("returns current index when queue length is 0", () => {
|
|
5
5
|
expect(getNextSessionIndex(0, 0)).toBe(0);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { DEFAULT_GRACE_PERIOD, formatStaleToastMessage, isSessionAbandoned, isSessionStale, } from "
|
|
2
|
+
import { DEFAULT_GRACE_PERIOD, formatStaleToastMessage, isSessionAbandoned, isSessionStale, } from "../../shared/utils/staleDetection.js";
|
|
3
3
|
describe("staleDetection", () => {
|
|
4
4
|
const now = new Date("2026-01-01T12:00:00.000Z");
|
|
5
5
|
beforeEach(() => {
|
|
@@ -1,80 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import * as path from "node:path";
|
|
3
|
-
import * as os from "node:os";
|
|
4
|
-
/**
|
|
5
|
-
* Get the config directory for AUQ
|
|
6
|
-
* Respects XDG_CONFIG_HOME on Linux, defaults to ~/.config/auq
|
|
7
|
-
*/
|
|
8
|
-
function getConfigDirectory() {
|
|
9
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME;
|
|
10
|
-
const baseConfig = xdgConfig || path.join(os.homedir(), ".config");
|
|
11
|
-
return path.join(baseConfig, "auq");
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Get the config file path
|
|
15
|
-
*/
|
|
16
|
-
function getConfigPath() {
|
|
17
|
-
return path.join(getConfigDirectory(), "config.json");
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Load config from file
|
|
21
|
-
* Returns empty config if file doesn't exist or is invalid
|
|
22
|
-
*/
|
|
23
|
-
export function loadConfig() {
|
|
24
|
-
try {
|
|
25
|
-
const configPath = getConfigPath();
|
|
26
|
-
if (!fs.existsSync(configPath)) {
|
|
27
|
-
return {};
|
|
28
|
-
}
|
|
29
|
-
const content = fs.readFileSync(configPath, "utf-8");
|
|
30
|
-
const data = JSON.parse(content);
|
|
31
|
-
if (typeof data !== "object" || data === null) {
|
|
32
|
-
return {};
|
|
33
|
-
}
|
|
34
|
-
return data;
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
// Silently return empty config on any error
|
|
38
|
-
return {};
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Save config to file
|
|
43
|
-
* Creates the config directory if it doesn't exist
|
|
44
|
-
*/
|
|
45
|
-
export function saveConfig(config) {
|
|
46
|
-
try {
|
|
47
|
-
const configDir = getConfigDirectory();
|
|
48
|
-
const configPath = getConfigPath();
|
|
49
|
-
// Ensure directory exists
|
|
50
|
-
if (!fs.existsSync(configDir)) {
|
|
51
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
52
|
-
}
|
|
53
|
-
// Merge with existing config to preserve other settings
|
|
54
|
-
const existingConfig = loadConfig();
|
|
55
|
-
const mergedConfig = { ...existingConfig, ...config };
|
|
56
|
-
fs.writeFileSync(configPath, JSON.stringify(mergedConfig, null, 2) + "\n");
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
// Silently ignore save errors - config is optional
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Get saved theme from config
|
|
64
|
-
*/
|
|
65
|
-
export function getSavedTheme() {
|
|
66
|
-
const config = loadConfig();
|
|
67
|
-
return config.theme;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Save theme to config
|
|
71
|
-
*/
|
|
72
|
-
export function saveTheme(themeName) {
|
|
73
|
-
saveConfig({ theme: themeName });
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Get the config directory path (for display purposes)
|
|
77
|
-
*/
|
|
78
|
-
export function getConfigDirectoryPath() {
|
|
79
|
-
return getConfigDirectory();
|
|
80
|
-
}
|
|
1
|
+
export * from "../shared/utils/config.js";
|
|
@@ -1,22 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export function detectSystemTheme() {
|
|
3
|
-
if (cachedResult !== null) {
|
|
4
|
-
return cachedResult;
|
|
5
|
-
}
|
|
6
|
-
const colorfgbg = process.env.COLORFGBG;
|
|
7
|
-
if (colorfgbg) {
|
|
8
|
-
const parts = colorfgbg.split(";");
|
|
9
|
-
if (parts.length >= 2) {
|
|
10
|
-
const bg = parseInt(parts[1], 10);
|
|
11
|
-
if (!isNaN(bg)) {
|
|
12
|
-
cachedResult = bg < 8 ? "AUQ dark" : "AUQ light";
|
|
13
|
-
return cachedResult;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
cachedResult = "AUQ dark";
|
|
18
|
-
return cachedResult;
|
|
19
|
-
}
|
|
20
|
-
export function clearDetectionCache() {
|
|
21
|
-
cachedResult = null;
|
|
22
|
-
}
|
|
1
|
+
export * from "../shared/utils/detectTheme.js";
|
|
@@ -1,52 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Utility for detecting recommended options in question labels.
|
|
3
|
-
* Supports multiple languages and bracket styles.
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Regex patterns for detecting recommended markers in labels.
|
|
7
|
-
* Requires matching delimiters: either (word) or [word].
|
|
8
|
-
* Matches case-insensitively and supports both parentheses and brackets.
|
|
9
|
-
*/
|
|
10
|
-
export const RECOMMENDED_PATTERNS = {
|
|
11
|
-
/** Matches (recommended) or [recommended] - case insensitive, requires matching delimiters */
|
|
12
|
-
EN: /(?:\(recommended\)|\[recommended\])/i,
|
|
13
|
-
/** Matches (추천) or [추천] - requires matching delimiters */
|
|
14
|
-
KO: /(?:\(추천\)|\[추천\])/,
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* Combined regex for detecting any recommended pattern.
|
|
18
|
-
* Requires matching delimiters: either (word) or [word].
|
|
19
|
-
* Matches case-insensitively for English, exactly for Korean.
|
|
20
|
-
*/
|
|
21
|
-
const RECOMMENDED_REGEX = /(?:\(recommended\)|\[recommended\]|\(추천\)|\[추천\])/i;
|
|
22
|
-
/**
|
|
23
|
-
* Detects if a label contains a recommended pattern.
|
|
24
|
-
* Supports English "recommended" and Korean "추천" in parentheses or brackets.
|
|
25
|
-
* Case-insensitive matching.
|
|
26
|
-
*
|
|
27
|
-
* @param label - The option label to check
|
|
28
|
-
* @returns true if the label contains a recommended marker
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* isRecommendedOption("Option A (recommended)") // true
|
|
32
|
-
* isRecommendedOption("[추천] Option B") // true
|
|
33
|
-
* isRecommendedOption("Option C") // false
|
|
34
|
-
*/
|
|
35
|
-
export function isRecommendedOption(label) {
|
|
36
|
-
return RECOMMENDED_REGEX.test(label);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Extracts the clean label by removing recommended markers.
|
|
40
|
-
* Removes recommended patterns and trims whitespace.
|
|
41
|
-
*
|
|
42
|
-
* @param label - The option label with potential recommended marker
|
|
43
|
-
* @returns The clean label without recommended markers
|
|
44
|
-
*
|
|
45
|
-
* @example
|
|
46
|
-
* extractCleanLabel("Option A (recommended)") // "Option A"
|
|
47
|
-
* extractCleanLabel("[추천] Option B") // "Option B"
|
|
48
|
-
* extractCleanLabel(" Option C ") // "Option C"
|
|
49
|
-
*/
|
|
50
|
-
export function extractCleanLabel(label) {
|
|
51
|
-
return label.replace(RECOMMENDED_REGEX, "").trim().replace(/\s+/g, " ");
|
|
52
|
-
}
|
|
1
|
+
export * from "../shared/utils/recommended.js";
|
|
@@ -1,24 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Format a timestamp as a concise relative time string.
|
|
3
|
-
*
|
|
4
|
-
* @param date - A Date object or a numeric epoch-ms timestamp
|
|
5
|
-
* @returns Human-readable label such as "just now", "12s ago", "3m ago"
|
|
6
|
-
*/
|
|
7
|
-
export function formatRelativeTime(date) {
|
|
8
|
-
const now = Date.now();
|
|
9
|
-
const then = typeof date === "number" ? date : date.getTime();
|
|
10
|
-
const diffMs = Math.max(0, now - then);
|
|
11
|
-
const diffSec = Math.floor(diffMs / 1000);
|
|
12
|
-
if (diffSec < 5)
|
|
13
|
-
return "just now";
|
|
14
|
-
if (diffSec < 60)
|
|
15
|
-
return `${diffSec}s ago`;
|
|
16
|
-
const diffMin = Math.floor(diffSec / 60);
|
|
17
|
-
if (diffMin < 60)
|
|
18
|
-
return `${diffMin}m ago`;
|
|
19
|
-
const diffHr = Math.floor(diffMin / 60);
|
|
20
|
-
if (diffHr < 24)
|
|
21
|
-
return `${diffHr}h ago`;
|
|
22
|
-
const diffDay = Math.floor(diffHr / 24);
|
|
23
|
-
return `${diffDay}d ago`;
|
|
24
|
-
}
|
|
1
|
+
export * from "../shared/utils/relativeTime.js";
|
|
@@ -1,56 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Calculate the next session index with cyclic wrap-around.
|
|
3
|
-
* Returns current index if queue has <= 1 item.
|
|
4
|
-
*/
|
|
5
|
-
export function getNextSessionIndex(currentIndex, queueLength) {
|
|
6
|
-
if (queueLength <= 1) {
|
|
7
|
-
return currentIndex;
|
|
8
|
-
}
|
|
9
|
-
return (currentIndex + 1) % queueLength;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Calculate the previous session index with cyclic wrap-around.
|
|
13
|
-
* Returns current index if queue has <= 1 item.
|
|
14
|
-
*/
|
|
15
|
-
export function getPrevSessionIndex(currentIndex, queueLength) {
|
|
16
|
-
if (queueLength <= 1) {
|
|
17
|
-
return currentIndex;
|
|
18
|
-
}
|
|
19
|
-
return (currentIndex - 1 + queueLength) % queueLength;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Validate and return the target index for a direct jump (1-based input).
|
|
23
|
-
* Returns null if the jump is invalid (out of range, same as current).
|
|
24
|
-
*/
|
|
25
|
-
export function getDirectJumpIndex(keyNumber, currentIndex, queueLength) {
|
|
26
|
-
if (keyNumber < 1 || keyNumber > 9) {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
const targetIndex = keyNumber - 1;
|
|
30
|
-
if (targetIndex >= queueLength) {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
if (targetIndex === currentIndex) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
return targetIndex;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Calculate the new active session index after removing a session.
|
|
40
|
-
* Handles: removal before active, removal at active, removal after active, queue becoming empty.
|
|
41
|
-
*/
|
|
42
|
-
export function getAdjustedIndexAfterRemoval(removedIndex, activeIndex, newQueueLength) {
|
|
43
|
-
if (newQueueLength === 0) {
|
|
44
|
-
return 0;
|
|
45
|
-
}
|
|
46
|
-
if (removedIndex < activeIndex) {
|
|
47
|
-
return activeIndex - 1;
|
|
48
|
-
}
|
|
49
|
-
if (removedIndex > activeIndex) {
|
|
50
|
-
return activeIndex;
|
|
51
|
-
}
|
|
52
|
-
if (removedIndex < newQueueLength) {
|
|
53
|
-
return removedIndex;
|
|
54
|
-
}
|
|
55
|
-
return newQueueLength - 1;
|
|
56
|
-
}
|
|
1
|
+
export * from "../shared/utils/sessionSwitching.js";
|