-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmcode-hub
More file actions
executable file
·106 lines (97 loc) · 4.43 KB
/
Copy pathmcode-hub
File metadata and controls
executable file
·106 lines (97 loc) · 4.43 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
#!/usr/bin/env node
// mcode-hub — the `custom-command` target for mcode 0.4.0+.
//
// mcode runs this on startup, on session/workspace change, and every
// `intervalSeconds`, writing one JSON line to stdin and rendering the first
// `maxLines` lines of stdout underneath its built-in status row:
//
// {"protocol":1,"event":"interval","session_id":"mvs_…",
// "workspace_dir":"/path","model":"MiniMax-M3","session_title":"…",
// "tui_version":"0.4.0"}
//
// We answer with the same three rows the fork used to inject:
//
// 会话 tokens 644.88M 「输入 8.01M │ 输出 1.41M │ 缓存 635.45M」 │ 上下文 43% 「425.84K/1.00M」 │ 缓存命中 99% │ 轮数 97
// 小时会话窗口 [███████████░░░░░░░░░] 55% 剩余 │ 重置 2h 6m │ 周限制使用量 [███████████████████░] 97% 剩余 │ 重置 2d 11h
// 今日 「MiniMax-M3」 170.19M │ 「deepseek-flash」 53.25M
//
// Nothing here patches mcode. Configure it via install via `mcode-hub-install` (see
// config/0.4.0/tui.statusline.yaml) and plain `mcode` shows the rows.
//
// Exit behaviour: print nothing and exit 0 on any problem. mcode renders an
// empty block rather than an error, so a broken status script can never take
// the TUI down with it — the same containment the fork's try/catch provided.
import { buildStatusLines } from "./lib/render.mjs";
import { collect, DEFAULT_DB } from "./lib/data.mjs";
import { loadMcodexOptions } from "./lib/options.mjs";
const DEBUG = process.env.MCODEX_STATUS_DEBUG === "1";
const log = (m) => { if (DEBUG) process.stderr.write("[mcode-hub] " + m + "\n"); };
function readStdin() {
return new Promise((resolve) => {
let buf = "";
let done = false;
const finish = () => { if (!done) { done = true; resolve(buf); } };
// No stdin (or a TTY): don't hang. mcode always writes a line, so this is
// only for manual invocation.
if (process.stdin.isTTY) { finish(); return; }
process.stdin.setEncoding("utf-8");
process.stdin.on("data", (c) => {
buf += c;
if (buf.includes("\n")) { try { process.stdin.pause(); } catch {} finish(); }
});
process.stdin.on("end", finish);
process.stdin.on("error", finish);
setTimeout(finish, 3000).unref?.();
});
}
function width() {
const env = Number(process.env.COLUMNS);
if (Number.isFinite(env) && env > 0) return env;
const t = Number(process.stdout.columns);
if (Number.isFinite(t) && t > 0) return t;
return 120; // mcode truncates to the real width anyway
}
async function main() {
const raw = await readStdin();
let payload = null;
try { payload = JSON.parse(raw.trim().split("\n").pop() || "{}"); } catch { payload = null; }
if (!payload) { log("no/invalid stdin payload"); return; }
const sessionId = payload.session_id || "";
log("event=" + payload.event + " session=" + sessionId + " model=" + payload.model);
// Always go through collect(), even with an empty sessionId. The data layer
// is built so quota (5h/周, from mmx) and today-by-model (aggregate sqlite)
// work fine without a session; only session-totals + context-window need a
// real sessionId and they short-circuit to null when missing. The renderer
// then prints "会话 tokens … │ 上下文 … │ 缓存命中 … │ 轮数 …" for the
// 4-chunk row and the real quota + today rows below.
//
// Net effect on the picker / welcome screen: the user sees a real 3-line
// statusline with one placeholder row + two live data rows, instead of
// either an empty bar (mcode 0.4.x collapses it) or a fully-fake skeleton.
let state;
try {
state = await collect({ sessionId, dbPath: process.env.MCODE_QUOTA_SQLITE || DEFAULT_DB });
} catch (e) {
log("collect failed: " + (e && e.message));
return;
}
let lines = [];
try {
// Per-category visibility + tailMode/decimals come from `tui.mcode-hub` in
// ~/.minimax/config.yaml. Re-read every tick so toggles take effect on
// the next 10s interval without restarting mcode.
let opts = {};
try {
opts = loadMcodexOptions();
} catch (e) {
log("options load failed: " + (e && e.message));
}
lines = buildStatusLines(state, width(), opts);
} catch (e) {
log("render failed: " + (e && e.stack || e));
return;
}
if (!lines.length) return;
process.stdout.write(lines.join("\n") + "\n");
}
main().catch((e) => { log("fatal: " + (e && e.stack || e)); });