-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathtui.ts
More file actions
121 lines (104 loc) · 3.1 KB
/
Copy pathtui.ts
File metadata and controls
121 lines (104 loc) · 3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { appendFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { createQuotaMonitor } from "./lib/codex-usage-monitor.js";
import { probeQuota } from "./lib/codex-usage-probe.js";
import { resolveSignalPath } from "./lib/codex-usage-signal.js";
import { resolveToastDurationMs } from "./lib/quota-settings.js";
type TuiToast = {
title?: string;
message: string;
variant?: "info" | "success" | "warning" | "error";
duration?: number;
};
type TuiApi = {
command: {
register: (
callback: () => Array<{
title: string;
value: string;
description: string;
category: string;
slash: { name: string };
onSelect: () => void;
}>,
) => () => void;
};
ui: {
toast: (input: TuiToast) => void;
};
lifecycle: {
onDispose: (dispose: () => void) => () => void;
};
};
const TUI_DEBUG_ENV = "OPENCODE_CODEX_USAGE_TUI_DEBUG";
const debugLogPath = path.join(os.tmpdir(), "opencode-codex-usage-tui-debug.log");
const debugEnabled = (): boolean => {
const value = process.env[TUI_DEBUG_ENV]?.trim().toLowerCase();
return value === "1" || value === "true" || value === "yes";
};
const debugLog = (
message: string,
extra: {
hasCommandRegister?: string;
hasToast?: string;
detail?: string;
value?: string;
slashName?: string;
} = {},
): void => {
if (!debugEnabled()) return;
const line = JSON.stringify({ time: new Date().toISOString(), message, ...extra });
void appendFile(debugLogPath, `${line}\n`, "utf8").catch(() => undefined);
};
export const CodexQuotaTuiPlugin = async (api: TuiApi): Promise<void> => {
const toastDurationMs = resolveToastDurationMs();
debugLog("tui plugin loaded", {
hasCommandRegister: typeof api.command?.register,
hasToast: typeof api.ui?.toast,
});
if (debugEnabled()) {
api.ui.toast({
title: "Codex usage debug",
message: `/codex-usage TUI plugin loaded; log: ${debugLogPath}`,
variant: "info",
duration: 10_000,
});
}
const monitor = createQuotaMonitor({
probe: probeQuota,
notify: (toast) => api.ui.toast(toast),
logError: (message, detail) => debugLog(message, { detail }),
pollMs: 10 * 60 * 1000,
threshold: "never",
durationMs: toastDurationMs,
signalPath: resolveSignalPath(),
});
const dispose = api.command.register(() => [
...(() => {
const command = {
title: "Codex usage",
value: "codex-usage",
description: "Show Codex quota",
category: "Codex",
slash: { name: "codex-usage" },
onSelect: () => {
debugLog("command selected");
void monitor.refresh({ force: true, showFailure: true });
},
};
debugLog("register callback returned command", {
value: command.value,
slashName: command.slash.name,
});
return [command];
})(),
]);
debugLog("command registered");
api.lifecycle.onDispose(() => {
debugLog("tui plugin disposed");
monitor.stop();
dispose();
});
};
export default { id: "opencode-codex-usage", tui: CodexQuotaTuiPlugin };