pinglet-cli 0.6.2 → 0.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.ja.md +46 -2
- package/README.ko.md +46 -2
- package/README.md +54 -3
- package/dist/adapters/claude.js +25 -2
- package/dist/cli.js +16 -5
- package/dist/commands/doctor.js +3 -0
- package/dist/commands/hud.js +247 -0
- package/dist/commands/refresh.js +6 -0
- package/dist/commands/statusline.js +29 -6
- package/dist/config.js +1 -0
- package/dist/hud/colors.js +81 -0
- package/dist/hud/config.js +300 -0
- package/dist/hud/git.js +218 -0
- package/dist/hud/index.js +41 -0
- package/dist/hud/labels.js +95 -0
- package/dist/hud/memory.js +123 -0
- package/dist/hud/render.js +787 -0
- package/dist/hud/speed.js +109 -0
- package/dist/hud/stdin.js +134 -0
- package/dist/hud/transcript.js +481 -0
- package/dist/hud/width.js +194 -0
- package/dist/i18n.js +94 -0
- package/package.json +1 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadHudConfig = loadHudConfig;
|
|
4
|
+
exports.renderHudLines = renderHudLines;
|
|
5
|
+
const config_1 = require("./config");
|
|
6
|
+
const git_1 = require("./git");
|
|
7
|
+
const memory_1 = require("./memory");
|
|
8
|
+
const render_1 = require("./render");
|
|
9
|
+
const speed_1 = require("./speed");
|
|
10
|
+
const transcript_1 = require("./transcript");
|
|
11
|
+
/** config.json의 `hud` 섹션을 정규화해 돌려준다 (없으면 기본값 = full 프리셋). */
|
|
12
|
+
function loadHudConfig(config) {
|
|
13
|
+
return (0, config_1.normalizeHudConfig)(config.hud);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* statusline tick에서 호출 — payload가 없으면(수동 실행 등) HUD 줄을 그리지 않는다.
|
|
17
|
+
* transcript는 비동기 스트림으로, git은 비동기 서브프로세스로 읽으며 네트워크는 쓰지 않는다.
|
|
18
|
+
* 로컬 잠금 밖에서 실행되므로 다른 훅을 막지 않는다.
|
|
19
|
+
*/
|
|
20
|
+
async function renderHudLines(hud, payload, now = Date.now()) {
|
|
21
|
+
if (!hud.enabled)
|
|
22
|
+
return [];
|
|
23
|
+
const hasPayload = !!(payload.model || payload.context_window || payload.cwd || payload.transcript_path);
|
|
24
|
+
if (!hasPayload)
|
|
25
|
+
return [];
|
|
26
|
+
const { display, gitStatus } = hud;
|
|
27
|
+
const needsTranscript = display.showTools || display.showSkills || display.showAgents || display.showTodos ||
|
|
28
|
+
display.showSessionName || display.showDuration || display.showPromptCache || display.showAdvisor ||
|
|
29
|
+
display.showSessionTokens || display.showCompactions || display.showEffortLevel;
|
|
30
|
+
const transcriptPath = typeof payload.transcript_path === "string" ? payload.transcript_path : undefined;
|
|
31
|
+
const cwd = typeof payload.cwd === "string" ? payload.cwd : payload.workspace?.current_dir;
|
|
32
|
+
const [transcript, git] = await Promise.all([
|
|
33
|
+
needsTranscript ? (0, transcript_1.parseTranscript)(transcriptPath) : Promise.resolve({ tools: [], agents: [], todos: [], skills: [] }),
|
|
34
|
+
gitStatus.enabled ? (0, git_1.getGitStatus)(cwd) : Promise.resolve(null),
|
|
35
|
+
]);
|
|
36
|
+
const memory = display.showMemoryUsage && hud.lineLayout === "expanded" && hud.elementOrder.includes("memory")
|
|
37
|
+
? (0, memory_1.getMemoryUsage)(now)
|
|
38
|
+
: null;
|
|
39
|
+
const speed = display.showSpeed ? (0, speed_1.getOutputSpeed)(payload, now) : null;
|
|
40
|
+
return (0, render_1.renderHud)({ config: hud, payload, transcript, gitStatus: git, memory, speed, now });
|
|
41
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hudLabel = hudLabel;
|
|
4
|
+
exports.resetHudLabels = resetHudLabels;
|
|
5
|
+
const render_1 = require("../render");
|
|
6
|
+
/** HUD 고정 문구 — statusline 언어 판정(detectLocale)을 따른다. */
|
|
7
|
+
const TABLE = {
|
|
8
|
+
en: {
|
|
9
|
+
context: "Context",
|
|
10
|
+
usage: "Usage",
|
|
11
|
+
weekly: "Weekly",
|
|
12
|
+
resetsIn: "resets in",
|
|
13
|
+
resets: "resets",
|
|
14
|
+
at: "at",
|
|
15
|
+
limitReached: "Limit reached",
|
|
16
|
+
allTodosComplete: "All todos complete",
|
|
17
|
+
in: "in",
|
|
18
|
+
cache: "cache",
|
|
19
|
+
cost: "Cost",
|
|
20
|
+
more: "more",
|
|
21
|
+
skills: "Skills",
|
|
22
|
+
approxRam: "Approx RAM",
|
|
23
|
+
promptCache: "Cache",
|
|
24
|
+
until: "until",
|
|
25
|
+
expired: "expired",
|
|
26
|
+
hit: "hit",
|
|
27
|
+
advisor: "Advisor",
|
|
28
|
+
tokens: "Tokens",
|
|
29
|
+
tok: "tok",
|
|
30
|
+
out: "out",
|
|
31
|
+
tokPerSec: "tok/s",
|
|
32
|
+
compactions: "Compactions",
|
|
33
|
+
},
|
|
34
|
+
ko: {
|
|
35
|
+
context: "컨텍스트",
|
|
36
|
+
usage: "사용량",
|
|
37
|
+
weekly: "주간",
|
|
38
|
+
resetsIn: "리셋까지",
|
|
39
|
+
resets: "리셋",
|
|
40
|
+
at: "",
|
|
41
|
+
limitReached: "한도 도달",
|
|
42
|
+
allTodosComplete: "할 일 모두 완료",
|
|
43
|
+
in: "입력",
|
|
44
|
+
cache: "캐시",
|
|
45
|
+
cost: "비용",
|
|
46
|
+
more: "개 더",
|
|
47
|
+
skills: "스킬",
|
|
48
|
+
approxRam: "RAM",
|
|
49
|
+
promptCache: "캐시",
|
|
50
|
+
until: "만료",
|
|
51
|
+
expired: "만료됨",
|
|
52
|
+
hit: "히트",
|
|
53
|
+
advisor: "자문 모델",
|
|
54
|
+
tokens: "토큰",
|
|
55
|
+
tok: "토큰",
|
|
56
|
+
out: "출력",
|
|
57
|
+
tokPerSec: "tok/s",
|
|
58
|
+
compactions: "압축",
|
|
59
|
+
},
|
|
60
|
+
ja: {
|
|
61
|
+
context: "コンテキスト",
|
|
62
|
+
usage: "使用量",
|
|
63
|
+
weekly: "週間",
|
|
64
|
+
resetsIn: "リセットまで",
|
|
65
|
+
resets: "リセット",
|
|
66
|
+
at: "",
|
|
67
|
+
limitReached: "上限到達",
|
|
68
|
+
allTodosComplete: "Todo すべて完了",
|
|
69
|
+
in: "入力",
|
|
70
|
+
cache: "キャッシュ",
|
|
71
|
+
cost: "コスト",
|
|
72
|
+
more: "件",
|
|
73
|
+
skills: "スキル",
|
|
74
|
+
approxRam: "RAM",
|
|
75
|
+
promptCache: "キャッシュ",
|
|
76
|
+
until: "期限",
|
|
77
|
+
expired: "期限切れ",
|
|
78
|
+
hit: "ヒット",
|
|
79
|
+
advisor: "アドバイザー",
|
|
80
|
+
tokens: "トークン",
|
|
81
|
+
tok: "トークン",
|
|
82
|
+
out: "出力",
|
|
83
|
+
tokPerSec: "tok/s",
|
|
84
|
+
compactions: "圧縮",
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
let cached = null;
|
|
88
|
+
function hudLabel(key) {
|
|
89
|
+
cached ??= TABLE[(0, render_1.detectLocale)()];
|
|
90
|
+
return cached[key];
|
|
91
|
+
}
|
|
92
|
+
/** 테스트용 — 언어 판정 캐시를 비운다. */
|
|
93
|
+
function resetHudLabels() {
|
|
94
|
+
cached = null;
|
|
95
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseVmStat = parseVmStat;
|
|
37
|
+
exports.parseLinuxMeminfo = parseLinuxMeminfo;
|
|
38
|
+
exports.toMemoryInfo = toMemoryInfo;
|
|
39
|
+
exports.getMemoryUsage = getMemoryUsage;
|
|
40
|
+
exports.formatBytes = formatBytes;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const os = __importStar(require("os"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const child_process_1 = require("child_process");
|
|
45
|
+
const config_1 = require("../config");
|
|
46
|
+
const storage_1 = require("../storage");
|
|
47
|
+
const CACHE_PATH = path.join(config_1.PINGLET_DIR, "hud-cache", "memory.json");
|
|
48
|
+
const MEMORY_CACHE_MS = 5_000;
|
|
49
|
+
function parseVmStat(output) {
|
|
50
|
+
const pageSize = output.match(/page size of (\d+) bytes/);
|
|
51
|
+
const active = output.match(/Pages active:\s+(\d+)/);
|
|
52
|
+
const wired = output.match(/Pages wired down:\s+(\d+)/);
|
|
53
|
+
if (!pageSize || !active || !wired)
|
|
54
|
+
return null;
|
|
55
|
+
return { pageSize: Number(pageSize[1]), active: Number(active[1]), wired: Number(wired[1]) };
|
|
56
|
+
}
|
|
57
|
+
function parseLinuxMeminfo(output) {
|
|
58
|
+
const total = output.match(/^MemTotal:\s+(\d+)\s+kB/m);
|
|
59
|
+
const available = output.match(/^MemAvailable:\s+(\d+)\s+kB/m);
|
|
60
|
+
if (!total || !available)
|
|
61
|
+
return null;
|
|
62
|
+
return { totalBytes: Number(total[1]) * 1024, freeBytes: Number(available[1]) * 1024 };
|
|
63
|
+
}
|
|
64
|
+
function readRaw() {
|
|
65
|
+
const fallback = () => ({ totalBytes: os.totalmem(), freeBytes: os.freemem() });
|
|
66
|
+
try {
|
|
67
|
+
if (process.platform === "darwin") {
|
|
68
|
+
const parsed = parseVmStat((0, child_process_1.execFileSync)("/usr/bin/vm_stat", { encoding: "utf8", timeout: 2000, stdio: ["ignore", "pipe", "ignore"] }));
|
|
69
|
+
if (!parsed)
|
|
70
|
+
return fallback();
|
|
71
|
+
const totalBytes = os.totalmem();
|
|
72
|
+
return { totalBytes, freeBytes: totalBytes - (parsed.active + parsed.wired) * parsed.pageSize };
|
|
73
|
+
}
|
|
74
|
+
if (process.platform === "linux") {
|
|
75
|
+
return parseLinuxMeminfo(fs.readFileSync("/proc/meminfo", "utf8")) ?? fallback();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// 플랫폼 도구 실패 — Node 값으로.
|
|
80
|
+
}
|
|
81
|
+
return fallback();
|
|
82
|
+
}
|
|
83
|
+
function toMemoryInfo(raw) {
|
|
84
|
+
if (!Number.isFinite(raw.totalBytes) || raw.totalBytes <= 0)
|
|
85
|
+
return null;
|
|
86
|
+
const free = Number.isFinite(raw.freeBytes) ? Math.min(Math.max(raw.freeBytes, 0), raw.totalBytes) : 0;
|
|
87
|
+
const usedBytes = raw.totalBytes - free;
|
|
88
|
+
return {
|
|
89
|
+
totalBytes: raw.totalBytes,
|
|
90
|
+
usedBytes,
|
|
91
|
+
usedPercent: Math.min(100, Math.max(0, Math.round((usedBytes / raw.totalBytes) * 100))),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function getMemoryUsage(now = Date.now()) {
|
|
95
|
+
try {
|
|
96
|
+
const cached = JSON.parse(fs.readFileSync(CACHE_PATH, "utf8"));
|
|
97
|
+
if (cached && typeof cached.checkedAt === "number" && now - cached.checkedAt < MEMORY_CACHE_MS)
|
|
98
|
+
return cached.info;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// 캐시 없음
|
|
102
|
+
}
|
|
103
|
+
const info = toMemoryInfo(readRaw());
|
|
104
|
+
try {
|
|
105
|
+
(0, storage_1.atomicWrite)(CACHE_PATH, JSON.stringify({ checkedAt: now, info }));
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// 캐시 실패는 표시에 영향을 주면 안 된다.
|
|
109
|
+
}
|
|
110
|
+
return info;
|
|
111
|
+
}
|
|
112
|
+
function formatBytes(bytes) {
|
|
113
|
+
if (!Number.isFinite(bytes) || bytes <= 0)
|
|
114
|
+
return "0 B";
|
|
115
|
+
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
116
|
+
let value = bytes;
|
|
117
|
+
let unit = 0;
|
|
118
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
119
|
+
value /= 1024;
|
|
120
|
+
unit++;
|
|
121
|
+
}
|
|
122
|
+
return `${value.toFixed(value >= 10 || unit === 0 ? 0 : 1)} ${units[unit]}`;
|
|
123
|
+
}
|