auq-mcp-server 2.3.0 → 2.4.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.
Files changed (51) hide show
  1. package/README.md +82 -0
  2. package/dist/bin/auq.js +47 -93
  3. package/dist/bin/tui-app.js +69 -6
  4. package/dist/package.json +1 -1
  5. package/dist/src/__tests__/server.abort.test.js +214 -0
  6. package/dist/src/cli/commands/__tests__/answer.test.js +199 -0
  7. package/dist/src/cli/commands/__tests__/config.test.js +218 -0
  8. package/dist/src/cli/commands/__tests__/sessions.test.js +282 -0
  9. package/dist/src/cli/commands/answer.js +128 -0
  10. package/dist/src/cli/commands/config.js +263 -0
  11. package/dist/src/cli/commands/sessions.js +164 -0
  12. package/dist/src/cli/utils.js +95 -0
  13. package/dist/src/config/__tests__/ConfigLoader.test.js +41 -0
  14. package/dist/src/config/defaults.js +3 -0
  15. package/dist/src/config/types.js +4 -0
  16. package/dist/src/core/ask-user-questions.js +3 -2
  17. package/dist/src/i18n/locales/en.js +7 -0
  18. package/dist/src/i18n/locales/ko.js +7 -0
  19. package/dist/src/server.js +64 -11
  20. package/dist/src/session/SessionManager.js +69 -4
  21. package/dist/src/session/__tests__/SessionManager.test.js +65 -0
  22. package/dist/src/tui/__tests__/session-watcher.test.js +109 -0
  23. package/dist/src/tui/components/SessionDots.js +33 -4
  24. package/dist/src/tui/components/SessionPicker.js +25 -17
  25. package/dist/src/tui/components/Spinner.js +19 -0
  26. package/dist/src/tui/components/StepperView.js +68 -5
  27. package/dist/src/tui/components/__tests__/SessionDots.test.js +160 -1
  28. package/dist/src/tui/components/__tests__/SessionPicker.test.js +43 -1
  29. package/dist/src/tui/components/__tests__/StepperView.abandoned.test.js +160 -0
  30. package/dist/src/tui/components/__tests__/StepperView.state.test.js +1 -0
  31. package/dist/src/tui/session-watcher.js +50 -0
  32. package/dist/src/tui/themes/catppuccin-latte.js +7 -0
  33. package/dist/src/tui/themes/catppuccin-mocha.js +7 -0
  34. package/dist/src/tui/themes/dark.js +7 -0
  35. package/dist/src/tui/themes/dracula.js +7 -0
  36. package/dist/src/tui/themes/github-dark.js +7 -0
  37. package/dist/src/tui/themes/github-light.js +7 -0
  38. package/dist/src/tui/themes/gruvbox-dark.js +7 -0
  39. package/dist/src/tui/themes/gruvbox-light.js +7 -0
  40. package/dist/src/tui/themes/light.js +7 -0
  41. package/dist/src/tui/themes/monokai.js +7 -0
  42. package/dist/src/tui/themes/nord.js +7 -0
  43. package/dist/src/tui/themes/one-dark.js +7 -0
  44. package/dist/src/tui/themes/rose-pine.js +7 -0
  45. package/dist/src/tui/themes/solarized-dark.js +7 -0
  46. package/dist/src/tui/themes/solarized-light.js +7 -0
  47. package/dist/src/tui/themes/tokyo-night.js +7 -0
  48. package/dist/src/tui/utils/__tests__/detectTheme.test.js +78 -0
  49. package/dist/src/tui/utils/__tests__/staleDetection.test.js +118 -0
  50. package/dist/src/tui/utils/staleDetection.js +51 -0
  51. package/package.json +1 -1
@@ -29,7 +29,7 @@ function renderWithTheme(ui) {
29
29
  function getOutput(frame) {
30
30
  return (frame ?? "").replace(/\x1b\[[0-9;]*m/g, "").replace(/\r/g, "");
31
31
  }
32
- function createSession(id) {
32
+ function createSession(id, overrides) {
33
33
  return {
34
34
  sessionId: `picker-id-${id}`,
35
35
  sessionRequest: {
@@ -47,6 +47,7 @@ function createSession(id) {
47
47
  ],
48
48
  },
49
49
  timestamp: new Date("2026-01-01T00:00:00.000Z"),
50
+ ...overrides,
50
51
  };
51
52
  }
52
53
  afterEach(() => {
@@ -122,4 +123,45 @@ describe("SessionPicker", () => {
122
123
  expect(onClose).toHaveBeenCalledTimes(1);
123
124
  expect(onSelectIndex).not.toHaveBeenCalled();
124
125
  });
126
+ describe("stale/abandoned session indicators", () => {
127
+ it("shows ⚠ icon for stale sessions", () => {
128
+ const sessions = [createSession(1), createSession(2, { isStale: true })];
129
+ const instance = renderWithTheme(React.createElement(SessionPicker, { isOpen: true, sessions: sessions, activeIndex: 0, sessionUIStates: {}, onSelectIndex: () => { }, onClose: () => { } }));
130
+ const output = getOutput(instance.lastFrame());
131
+ expect(output).toContain("⚠");
132
+ expect(output).toContain("Title 2");
133
+ });
134
+ it("shows 'may be orphaned' subtitle for stale sessions", () => {
135
+ const sessions = [createSession(1, { isStale: true })];
136
+ const instance = renderWithTheme(React.createElement(SessionPicker, { isOpen: true, sessions: sessions, activeIndex: 0, sessionUIStates: {}, onSelectIndex: () => { }, onClose: () => { } }));
137
+ const output = getOutput(instance.lastFrame());
138
+ expect(output).toContain("may be orphaned");
139
+ });
140
+ it("shows 'session abandoned' subtitle for abandoned sessions", () => {
141
+ const sessions = [createSession(1, { isAbandoned: true })];
142
+ const instance = renderWithTheme(React.createElement(SessionPicker, { isOpen: true, sessions: sessions, activeIndex: 0, sessionUIStates: {}, onSelectIndex: () => { }, onClose: () => { } }));
143
+ const output = getOutput(instance.lastFrame());
144
+ expect(output).toContain("⚠");
145
+ expect(output).toContain("session abandoned");
146
+ });
147
+ it("stale sessions remain selectable via Enter", async () => {
148
+ const sessions = [createSession(1, { isStale: true }), createSession(2)];
149
+ const onSelectIndex = vi.fn();
150
+ const onClose = vi.fn();
151
+ renderWithTheme(React.createElement(SessionPicker, { isOpen: true, sessions: sessions, activeIndex: 0, sessionUIStates: {}, onSelectIndex: onSelectIndex, onClose: onClose }));
152
+ expect(inputState.handler).not.toBeNull();
153
+ inputState.handler("", { return: true });
154
+ await Promise.resolve();
155
+ expect(onSelectIndex).toHaveBeenCalledWith(0);
156
+ expect(onClose).toHaveBeenCalled();
157
+ });
158
+ it("non-stale sessions render normally without ⚠ or subtitles", () => {
159
+ const sessions = [createSession(1), createSession(2)];
160
+ const instance = renderWithTheme(React.createElement(SessionPicker, { isOpen: true, sessions: sessions, activeIndex: 0, sessionUIStates: {}, onSelectIndex: () => { }, onClose: () => { } }));
161
+ const output = getOutput(instance.lastFrame());
162
+ expect(output).not.toContain("⚠");
163
+ expect(output).not.toContain("may be orphaned");
164
+ expect(output).not.toContain("session abandoned");
165
+ });
166
+ });
125
167
  });
@@ -0,0 +1,160 @@
1
+ import React from "react";
2
+ import { cleanup, render } from "ink-testing-library";
3
+ import { afterEach, describe, expect, it, vi } from "vitest";
4
+ import { ConfigProvider } from "../../ConfigContext.js";
5
+ import { ThemeContext } from "../../ThemeContext.js";
6
+ import { darkTheme } from "../../themes/dark.js";
7
+ import { StepperView } from "../StepperView.js";
8
+ const mockThemeValue = {
9
+ theme: darkTheme,
10
+ themeName: "AUQ dark",
11
+ cycleTheme: () => { },
12
+ };
13
+ const sessionRequest = {
14
+ sessionId: "abandoned-test-session",
15
+ status: "pending",
16
+ timestamp: new Date().toISOString(),
17
+ callId: "call-abandoned-1",
18
+ questions: [
19
+ {
20
+ title: "Language",
21
+ prompt: "Pick a language",
22
+ options: [{ label: "TypeScript" }, { label: "Python" }],
23
+ },
24
+ {
25
+ title: "Framework",
26
+ prompt: "Pick a framework",
27
+ options: [{ label: "React" }, { label: "Vue" }],
28
+ },
29
+ ],
30
+ };
31
+ function renderStepper(props = {}) {
32
+ return render(React.createElement(ThemeContext.Provider, { value: mockThemeValue },
33
+ React.createElement(ConfigProvider, null,
34
+ React.createElement(StepperView, { sessionId: sessionRequest.sessionId, sessionRequest: sessionRequest, ...props }))));
35
+ }
36
+ function getOutput(frame) {
37
+ return (frame ?? "").replace(/\x1b\[[0-9;]*m/g, "").replace(/\r/g, "");
38
+ }
39
+ afterEach(() => {
40
+ cleanup();
41
+ vi.restoreAllMocks();
42
+ });
43
+ describe("StepperView abandoned session confirmation", () => {
44
+ it("shows abandoned confirmation dialog when isAbandoned is true", async () => {
45
+ const instance = renderStepper({ isAbandoned: true });
46
+ await vi.waitFor(() => {
47
+ const output = getOutput(instance.lastFrame());
48
+ expect(output).toContain("AI Disconnected");
49
+ });
50
+ const output = getOutput(instance.lastFrame());
51
+ expect(output).toContain("Answer anyway");
52
+ expect(output).toContain("Cancel");
53
+ // Should NOT show question content behind the dialog
54
+ expect(output).not.toContain("Pick a language");
55
+ });
56
+ it("does not show abandoned dialog when isAbandoned is false", () => {
57
+ const instance = renderStepper({ isAbandoned: false });
58
+ const output = getOutput(instance.lastFrame());
59
+ expect(output).not.toContain("AI Disconnected");
60
+ expect(output).toContain("Pick a language");
61
+ });
62
+ it("does not show abandoned dialog when isAbandoned is undefined", () => {
63
+ const instance = renderStepper();
64
+ const output = getOutput(instance.lastFrame());
65
+ expect(output).not.toContain("AI Disconnected");
66
+ expect(output).toContain("Pick a language");
67
+ });
68
+ it("selecting 'Answer anyway' dismisses dialog and shows questions", async () => {
69
+ const instance = renderStepper({ isAbandoned: true });
70
+ await vi.waitFor(() => {
71
+ const output = getOutput(instance.lastFrame());
72
+ expect(output).toContain("AI Disconnected");
73
+ });
74
+ // Press Enter to select the first option ("Answer anyway")
75
+ instance.stdin.write("\r");
76
+ await vi.waitFor(() => {
77
+ const output = getOutput(instance.lastFrame());
78
+ expect(output).toContain("Pick a language");
79
+ });
80
+ const output = getOutput(instance.lastFrame());
81
+ expect(output).not.toContain("AI Disconnected");
82
+ });
83
+ it("selecting 'Cancel' calls onAbandonedCancel", async () => {
84
+ const onAbandonedCancel = vi.fn();
85
+ const instance = renderStepper({
86
+ isAbandoned: true,
87
+ onAbandonedCancel,
88
+ });
89
+ await vi.waitFor(() => {
90
+ const output = getOutput(instance.lastFrame());
91
+ expect(output).toContain("AI Disconnected");
92
+ });
93
+ // Navigate down to "Cancel" then press Enter
94
+ // Use OA/OB sequences which ink reliably parses as arrows
95
+ instance.stdin.write("\x1bOB"); // Down arrow (application mode)
96
+ await new Promise((r) => setTimeout(r, 100));
97
+ // Press Enter to select "Cancel"
98
+ instance.stdin.write("\r");
99
+ await vi.waitFor(() => {
100
+ expect(onAbandonedCancel).toHaveBeenCalledOnce();
101
+ });
102
+ });
103
+ it("pressing Escape calls onAbandonedCancel", async () => {
104
+ const onAbandonedCancel = vi.fn();
105
+ const instance = renderStepper({
106
+ isAbandoned: true,
107
+ onAbandonedCancel,
108
+ });
109
+ await vi.waitFor(() => {
110
+ const output = getOutput(instance.lastFrame());
111
+ expect(output).toContain("AI Disconnected");
112
+ });
113
+ // Press Escape
114
+ instance.stdin.write("\x1b");
115
+ await vi.waitFor(() => {
116
+ expect(onAbandonedCancel).toHaveBeenCalledOnce();
117
+ });
118
+ });
119
+ it("after confirming, dialog does not reappear for the same session", async () => {
120
+ const instance = renderStepper({ isAbandoned: true });
121
+ // Wait for dialog
122
+ await vi.waitFor(() => {
123
+ expect(getOutput(instance.lastFrame())).toContain("AI Disconnected");
124
+ });
125
+ // Confirm ("Answer anyway")
126
+ instance.stdin.write("\r");
127
+ // Wait for questions to appear
128
+ await vi.waitFor(() => {
129
+ expect(getOutput(instance.lastFrame())).toContain("Pick a language");
130
+ });
131
+ // The dialog should stay dismissed - verify questions are still shown
132
+ const output = getOutput(instance.lastFrame());
133
+ expect(output).toContain("Pick a language");
134
+ expect(output).not.toContain("AI Disconnected");
135
+ });
136
+ it("emits showAbandonedConfirm in onFlowStateChange", async () => {
137
+ const onFlowStateChange = vi.fn();
138
+ renderStepper({
139
+ isAbandoned: true,
140
+ onFlowStateChange,
141
+ });
142
+ await vi.waitFor(() => {
143
+ expect(onFlowStateChange).toHaveBeenCalledWith(expect.objectContaining({ showAbandonedConfirm: true }));
144
+ });
145
+ });
146
+ it("blocks keyboard navigation while dialog is shown", async () => {
147
+ const instance = renderStepper({ isAbandoned: true });
148
+ await vi.waitFor(() => {
149
+ expect(getOutput(instance.lastFrame())).toContain("AI Disconnected");
150
+ });
151
+ // Try Tab to navigate questions - should do nothing
152
+ instance.stdin.write("\t");
153
+ // Dialog should still be shown
154
+ await vi.waitFor(() => {
155
+ const output = getOutput(instance.lastFrame());
156
+ expect(output).toContain("AI Disconnected");
157
+ expect(output).not.toContain("Pick a language");
158
+ });
159
+ });
160
+ });
@@ -96,6 +96,7 @@ describe("StepperView SessionUIState boundary", () => {
96
96
  expect(onFlowStateChange).toHaveBeenCalledWith({
97
97
  showReview: false,
98
98
  showRejectionConfirm: false,
99
+ showAbandonedConfirm: false,
99
100
  });
100
101
  });
101
102
  });
@@ -72,6 +72,56 @@ export class EnhancedTUISessionWatcher extends TUISessionWatcher {
72
72
  return [];
73
73
  }
74
74
  }
75
+ /**
76
+ * Get pending and abandoned sessions with full status metadata.
77
+ * Unlike getPendingSessions(), this includes abandoned sessions
78
+ * and returns status + createdAt for stale detection.
79
+ */
80
+ async getPendingSessionsWithStatus() {
81
+ const fs = await import("fs/promises");
82
+ const { join } = await import("path");
83
+ try {
84
+ const sessionDir = this.watchedPath;
85
+ const entries = await fs.readdir(sessionDir, { withFileTypes: true });
86
+ const results = [];
87
+ for (const entry of entries) {
88
+ if (!entry.isDirectory())
89
+ continue;
90
+ const sessionPath = join(sessionDir, entry.name);
91
+ const answersPath = join(sessionPath, SESSION_FILES.ANSWERS);
92
+ const statusPath = join(sessionPath, SESSION_FILES.STATUS);
93
+ try {
94
+ // Skip sessions that already have answers
95
+ await fs.access(answersPath);
96
+ }
97
+ catch {
98
+ // No answers file — read status.json
99
+ try {
100
+ const statusContent = await fs.readFile(statusPath, "utf-8");
101
+ const status = JSON.parse(statusContent);
102
+ // Include pending, in-progress, AND abandoned sessions
103
+ if (status.status === "pending" ||
104
+ status.status === "in-progress" ||
105
+ status.status === "abandoned") {
106
+ results.push({
107
+ createdAt: status.createdAt,
108
+ sessionId: entry.name,
109
+ status: status.status,
110
+ });
111
+ }
112
+ }
113
+ catch {
114
+ // No valid status file — skip
115
+ }
116
+ }
117
+ }
118
+ return results.sort((a, b) => a.sessionId.localeCompare(b.sessionId));
119
+ }
120
+ catch (error) {
121
+ console.warn("Failed to scan for pending sessions with status:", error);
122
+ return [];
123
+ }
124
+ }
75
125
  /**
76
126
  * Get session request data for a specific session
77
127
  */
@@ -91,6 +91,7 @@ export const catppuccinLatteTheme = {
91
91
  successPillBg: "#dce0e8",
92
92
  error: "#d20f39",
93
93
  info: "#1e66f5",
94
+ warning: "#df8e1d",
94
95
  border: "#ccd0da",
95
96
  },
96
97
  markdown: {
@@ -105,6 +106,8 @@ export const catppuccinLatteTheme = {
105
106
  untouched: "#acb0c0",
106
107
  number: "#4c4f69",
107
108
  activeNumber: "#1e66f5",
109
+ stale: "#df8e1d",
110
+ abandoned: "#d20f39",
108
111
  },
109
112
  sessionPicker: {
110
113
  border: "#1e66f5",
@@ -115,6 +118,10 @@ export const catppuccinLatteTheme = {
115
118
  highlightFg: "#40a02b",
116
119
  activeMark: "#1e66f5",
117
120
  progress: "#04a5e5",
121
+ staleIcon: "#df8e1d",
122
+ staleText: "#df8e1d",
123
+ staleAge: "#df8e1d",
124
+ staleSubtitle: "#acb0c0",
118
125
  },
119
126
  },
120
127
  };
@@ -91,6 +91,7 @@ export const catppuccinMochaTheme = {
91
91
  successPillBg: "#313244",
92
92
  error: "#f38ba8",
93
93
  info: "#89b4fa",
94
+ warning: "#f9e2af",
94
95
  border: "#313244",
95
96
  },
96
97
  markdown: {
@@ -105,6 +106,8 @@ export const catppuccinMochaTheme = {
105
106
  untouched: "#8688a0",
106
107
  number: "#cdd6f4",
107
108
  activeNumber: "#89b4fa",
109
+ stale: "#f9e2af",
110
+ abandoned: "#f38ba8",
108
111
  },
109
112
  sessionPicker: {
110
113
  border: "#89b4fa",
@@ -115,6 +118,10 @@ export const catppuccinMochaTheme = {
115
118
  highlightFg: "#a6e3a1",
116
119
  activeMark: "#89b4fa",
117
120
  progress: "#89dceb",
121
+ staleIcon: "#f9e2af",
122
+ staleText: "#f9e2af",
123
+ staleAge: "#f9e2af",
124
+ staleSubtitle: "#8688a0",
118
125
  },
119
126
  },
120
127
  };
@@ -92,6 +92,7 @@ export const darkTheme = {
92
92
  successPillBg: "#0F2417",
93
93
  error: "#FF5C57",
94
94
  info: "#46D9FF",
95
+ warning: "#FFD36A",
95
96
  border: "#2A3238",
96
97
  },
97
98
  markdown: {
@@ -106,6 +107,8 @@ export const darkTheme = {
106
107
  untouched: "#A0AAB4",
107
108
  number: "#E7EEF5",
108
109
  activeNumber: "#46D9FF",
110
+ stale: "#FFD36A",
111
+ abandoned: "#FF5C57",
109
112
  },
110
113
  sessionPicker: {
111
114
  border: "#46D9FF",
@@ -116,6 +119,10 @@ export const darkTheme = {
116
119
  highlightFg: "#5AF78E",
117
120
  activeMark: "#46D9FF",
118
121
  progress: "#46D9FF",
122
+ staleIcon: "#FFD36A",
123
+ staleText: "#FFD36A",
124
+ staleAge: "#FFD36A",
125
+ staleSubtitle: "#A0AAB4",
119
126
  },
120
127
  },
121
128
  };
@@ -91,6 +91,7 @@ export const draculaTheme = {
91
91
  successPillBg: "#44475a", // current line
92
92
  error: "#ff5555",
93
93
  info: "#bd93f9",
94
+ warning: "#f1fa8c",
94
95
  border: "#44475a",
95
96
  },
96
97
  markdown: {
@@ -105,6 +106,8 @@ export const draculaTheme = {
105
106
  untouched: "#7C8BBE",
106
107
  number: "#f8f8f2",
107
108
  activeNumber: "#bd93f9",
109
+ stale: "#f1fa8c",
110
+ abandoned: "#ff5555",
108
111
  },
109
112
  sessionPicker: {
110
113
  border: "#bd93f9",
@@ -115,6 +118,10 @@ export const draculaTheme = {
115
118
  highlightFg: "#50fa7b",
116
119
  activeMark: "#bd93f9",
117
120
  progress: "#8be9fd",
121
+ staleIcon: "#f1fa8c",
122
+ staleText: "#f1fa8c",
123
+ staleAge: "#f1fa8c",
124
+ staleSubtitle: "#7C8BBE",
118
125
  },
119
126
  },
120
127
  };
@@ -90,6 +90,7 @@ export const githubDarkTheme = {
90
90
  successPillBg: "#161b22",
91
91
  error: "#f85149",
92
92
  info: "#58a6ff",
93
+ warning: "#d29922",
93
94
  border: "#30363d",
94
95
  },
95
96
  markdown: {
@@ -104,6 +105,8 @@ export const githubDarkTheme = {
104
105
  untouched: "#a0a8b4",
105
106
  number: "#c9d1d9",
106
107
  activeNumber: "#58a6ff",
108
+ stale: "#d29922",
109
+ abandoned: "#f85149",
107
110
  },
108
111
  sessionPicker: {
109
112
  border: "#58a6ff",
@@ -114,6 +117,10 @@ export const githubDarkTheme = {
114
117
  highlightFg: "#3fb950",
115
118
  activeMark: "#58a6ff",
116
119
  progress: "#58a6ff",
120
+ staleIcon: "#d29922",
121
+ staleText: "#d29922",
122
+ staleAge: "#d29922",
123
+ staleSubtitle: "#a0a8b4",
117
124
  },
118
125
  },
119
126
  };
@@ -90,6 +90,7 @@ export const githubLightTheme = {
90
90
  successPillBg: "#f6f8fa",
91
91
  error: "#CF222E",
92
92
  info: "#0969DA",
93
+ warning: "#9A6700",
93
94
  border: "#D0D7DE",
94
95
  },
95
96
  markdown: {
@@ -104,6 +105,8 @@ export const githubLightTheme = {
104
105
  untouched: "#6E7781",
105
106
  number: "#24292F",
106
107
  activeNumber: "#0969DA",
108
+ stale: "#9A6700",
109
+ abandoned: "#CF222E",
107
110
  },
108
111
  sessionPicker: {
109
112
  border: "#0969DA",
@@ -114,6 +117,10 @@ export const githubLightTheme = {
114
117
  highlightFg: "#1A7F37",
115
118
  activeMark: "#0969DA",
116
119
  progress: "#0969DA",
120
+ staleIcon: "#9A6700",
121
+ staleText: "#9A6700",
122
+ staleAge: "#9A6700",
123
+ staleSubtitle: "#6E7781",
117
124
  },
118
125
  },
119
126
  };
@@ -91,6 +91,7 @@ export const gruvboxDarkTheme = {
91
91
  successPillBg: "#3c3836", // dark1
92
92
  error: "#cc241d",
93
93
  info: "#458588",
94
+ warning: "#d79921",
94
95
  border: "#3c3836",
95
96
  },
96
97
  markdown: {
@@ -105,6 +106,8 @@ export const gruvboxDarkTheme = {
105
106
  untouched: "#a89984",
106
107
  number: "#ebdbb2",
107
108
  activeNumber: "#458588",
109
+ stale: "#d79921",
110
+ abandoned: "#cc241d",
108
111
  },
109
112
  sessionPicker: {
110
113
  border: "#458588",
@@ -115,6 +118,10 @@ export const gruvboxDarkTheme = {
115
118
  highlightFg: "#98971a",
116
119
  activeMark: "#458588",
117
120
  progress: "#458588",
121
+ staleIcon: "#d79921",
122
+ staleText: "#d79921",
123
+ staleAge: "#d79921",
124
+ staleSubtitle: "#a89984",
118
125
  },
119
126
  },
120
127
  };
@@ -91,6 +91,7 @@ export const gruvboxLightTheme = {
91
91
  successPillBg: "#ebdbb2", // light1 - light bg
92
92
  error: "#9d0006",
93
93
  info: "#076678",
94
+ warning: "#b57614",
94
95
  border: "#d5c4a1",
95
96
  },
96
97
  markdown: {
@@ -105,6 +106,8 @@ export const gruvboxLightTheme = {
105
106
  untouched: "#a89984",
106
107
  number: "#3c3836",
107
108
  activeNumber: "#076678",
109
+ stale: "#b57614",
110
+ abandoned: "#9d0006",
108
111
  },
109
112
  sessionPicker: {
110
113
  border: "#076678",
@@ -115,6 +118,10 @@ export const gruvboxLightTheme = {
115
118
  highlightFg: "#79740e",
116
119
  activeMark: "#076678",
117
120
  progress: "#076678",
121
+ staleIcon: "#b57614",
122
+ staleText: "#b57614",
123
+ staleAge: "#b57614",
124
+ staleSubtitle: "#a89984",
118
125
  },
119
126
  },
120
127
  };
@@ -91,6 +91,7 @@ export const lightTheme = {
91
91
  successPillBg: "#E6F9EE",
92
92
  error: "#CF222E",
93
93
  info: "#007EA7",
94
+ warning: "#B07D00",
94
95
  border: "#D0D7DE",
95
96
  },
96
97
  markdown: {
@@ -105,6 +106,8 @@ export const lightTheme = {
105
106
  untouched: "#6E7781",
106
107
  number: "#24292F",
107
108
  activeNumber: "#007EA7",
109
+ stale: "#B07D00",
110
+ abandoned: "#CF222E",
108
111
  },
109
112
  sessionPicker: {
110
113
  border: "#007EA7",
@@ -115,6 +118,10 @@ export const lightTheme = {
115
118
  highlightFg: "#2DA44E",
116
119
  activeMark: "#007EA7",
117
120
  progress: "#007EA7",
121
+ staleIcon: "#B07D00",
122
+ staleText: "#B07D00",
123
+ staleAge: "#B07D00",
124
+ staleSubtitle: "#6E7781",
118
125
  },
119
126
  },
120
127
  };
@@ -92,6 +92,7 @@ export const monokaiTheme = {
92
92
  successPillBg: "#272822",
93
93
  error: "#F92672",
94
94
  info: "#66D9EF",
95
+ warning: "#E6DB74",
95
96
  border: "#49483E",
96
97
  },
97
98
  markdown: {
@@ -106,6 +107,8 @@ export const monokaiTheme = {
106
107
  untouched: "#908B78",
107
108
  number: "#F8F8F2",
108
109
  activeNumber: "#66D9EF",
110
+ stale: "#E6DB74",
111
+ abandoned: "#F92672",
109
112
  },
110
113
  sessionPicker: {
111
114
  border: "#66D9EF",
@@ -116,6 +119,10 @@ export const monokaiTheme = {
116
119
  highlightFg: "#A6E22E",
117
120
  activeMark: "#66D9EF",
118
121
  progress: "#66D9EF",
122
+ staleIcon: "#E6DB74",
123
+ staleText: "#E6DB74",
124
+ staleAge: "#E6DB74",
125
+ staleSubtitle: "#908B78",
119
126
  },
120
127
  },
121
128
  };
@@ -91,6 +91,7 @@ export const nordTheme = {
91
91
  successPillBg: "#3b4252", // nord1
92
92
  error: "#bf616a", // nord11
93
93
  info: "#88c0d0", // nord8
94
+ warning: "#ebcb8b",
94
95
  border: "#3b4252", // nord1
95
96
  },
96
97
  markdown: {
@@ -105,6 +106,8 @@ export const nordTheme = {
105
106
  untouched: "#616E88",
106
107
  number: "#eceff4",
107
108
  activeNumber: "#88c0d0",
109
+ stale: "#ebcb8b",
110
+ abandoned: "#bf616a",
108
111
  },
109
112
  sessionPicker: {
110
113
  border: "#88c0d0",
@@ -115,6 +118,10 @@ export const nordTheme = {
115
118
  highlightFg: "#a3be8c",
116
119
  activeMark: "#88c0d0",
117
120
  progress: "#81a1c1",
121
+ staleIcon: "#ebcb8b",
122
+ staleText: "#ebcb8b",
123
+ staleAge: "#ebcb8b",
124
+ staleSubtitle: "#616E88",
118
125
  },
119
126
  },
120
127
  };
@@ -91,6 +91,7 @@ export const oneDarkTheme = {
91
91
  successPillBg: "#282c34",
92
92
  error: "#e06c75",
93
93
  info: "#61afef",
94
+ warning: "#d19a66",
94
95
  border: "#3e4451",
95
96
  },
96
97
  markdown: {
@@ -105,6 +106,8 @@ export const oneDarkTheme = {
105
106
  untouched: "#767D8A",
106
107
  number: "#abb2bf",
107
108
  activeNumber: "#61afef",
109
+ stale: "#d19a66",
110
+ abandoned: "#e06c75",
108
111
  },
109
112
  sessionPicker: {
110
113
  border: "#61afef",
@@ -115,6 +118,10 @@ export const oneDarkTheme = {
115
118
  highlightFg: "#98c379",
116
119
  activeMark: "#61afef",
117
120
  progress: "#56b6c2",
121
+ staleIcon: "#d19a66",
122
+ staleText: "#d19a66",
123
+ staleAge: "#d19a66",
124
+ staleSubtitle: "#767D8A",
118
125
  },
119
126
  },
120
127
  };
@@ -92,6 +92,7 @@ export const rosePineTheme = {
92
92
  successPillBg: "#191724",
93
93
  error: "#eb6f92",
94
94
  info: "#9ccfd8",
95
+ warning: "#f6c177",
95
96
  border: "#26233a",
96
97
  },
97
98
  markdown: {
@@ -106,6 +107,8 @@ export const rosePineTheme = {
106
107
  untouched: "#8884a0",
107
108
  number: "#e0def4",
108
109
  activeNumber: "#ebbcba",
110
+ stale: "#f6c177",
111
+ abandoned: "#eb6f92",
109
112
  },
110
113
  sessionPicker: {
111
114
  border: "#ebbcba",
@@ -116,6 +119,10 @@ export const rosePineTheme = {
116
119
  highlightFg: "#31748f",
117
120
  activeMark: "#ebbcba",
118
121
  progress: "#9ccfd8",
122
+ staleIcon: "#f6c177",
123
+ staleText: "#f6c177",
124
+ staleAge: "#f6c177",
125
+ staleSubtitle: "#8884a0",
119
126
  },
120
127
  },
121
128
  };