negotium 0.6.7 → 0.6.9
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/dist/agent-helpers.js +2 -2
- package/dist/agent-helpers.js.map +2 -2
- package/dist/{chunk-f124y9d0.js → chunk-bhxdah5c.js} +2 -2
- package/dist/{chunk-f124y9d0.js.map → chunk-bhxdah5c.js.map} +2 -2
- package/dist/hosted-agent.js +2 -2
- package/dist/hosted-agent.js.map +2 -2
- package/dist/main.js +73 -20
- package/dist/main.js.map +5 -5
- package/dist/mcp-factories.js +68 -16
- package/dist/mcp-factories.js.map +4 -4
- package/dist/registry.js +1 -1
- package/dist/runtime/src/mcp/factories/system-health.ts +118 -16
- package/dist/runtime/src/version.ts +1 -1
- package/dist/types/packages/core/src/mcp/factories/system-health.d.ts +23 -3
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/registry.js
CHANGED
|
@@ -133,7 +133,7 @@ var codexRegistryOperations = {
|
|
|
133
133
|
return { sessionId: threadId, rolloutPath };
|
|
134
134
|
},
|
|
135
135
|
async forkSession({ parentSessionId }) {
|
|
136
|
-
const { forkCodexSession } = await import("./chunk-
|
|
136
|
+
const { forkCodexSession } = await import("./chunk-bhxdah5c.js");
|
|
137
137
|
return await forkCodexSession(parentSessionId);
|
|
138
138
|
},
|
|
139
139
|
async cleanupRollouts({ sessionIds }) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
-
import { cpus,
|
|
2
|
+
import { cpus, loadavg } from "node:os";
|
|
3
3
|
import { promisify } from "node:util";
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { errMsg } from "#platform/error";
|
|
@@ -7,12 +7,34 @@ import { mcpOk } from "../mcp-helpers";
|
|
|
7
7
|
|
|
8
8
|
const execFileAsync = promisify(execFile);
|
|
9
9
|
|
|
10
|
+
export interface SystemHealthMemory {
|
|
11
|
+
/** 앱 실사용 (btop 방식, 회수 불가) = active + wired */
|
|
12
|
+
usedBytes: number;
|
|
13
|
+
/** 파일 캐시/버퍼 등 압박 시 즉시 반환 가능 = inactive + speculative + purgeable */
|
|
14
|
+
cacheBytes: number;
|
|
15
|
+
/** 압축된 익명 메모리 (스왑 압박 시 지표) */
|
|
16
|
+
compressorBytes: number;
|
|
17
|
+
/** available = total - used(active+wired) */
|
|
18
|
+
availableBytes: number;
|
|
19
|
+
totalBytes: number;
|
|
20
|
+
/** active만 (breakdown 표시용) */
|
|
21
|
+
activeBytes: number;
|
|
22
|
+
/** wired만 (breakdown 표시용) */
|
|
23
|
+
wiredBytes: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface SystemHealthMemoryPressure {
|
|
27
|
+
/** normal / warning / critical / unknown */
|
|
28
|
+
level: string;
|
|
29
|
+
/** macOS 공식 "System-wide memory free percentage" (0~100), 없으면 null */
|
|
30
|
+
freePct: number | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
10
33
|
export interface SystemHealthSnapshot {
|
|
11
34
|
cpuLoad: [number, number, number];
|
|
12
35
|
cpuCount: number;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
memoryPressure: string;
|
|
36
|
+
memory: SystemHealthMemory;
|
|
37
|
+
memoryPressure: SystemHealthMemoryPressure;
|
|
16
38
|
swap: string;
|
|
17
39
|
disk: string;
|
|
18
40
|
thermal: string;
|
|
@@ -33,13 +55,82 @@ async function shell(command: string, args: string[]): Promise<string> {
|
|
|
33
55
|
return stdout.trim();
|
|
34
56
|
}
|
|
35
57
|
|
|
36
|
-
async function getMemoryPressure(): Promise<
|
|
58
|
+
async function getMemoryPressure(): Promise<SystemHealthMemoryPressure> {
|
|
59
|
+
// level: 스와핑 압박 레벨 (macOS가 실제 판정하는 공식 지표)
|
|
60
|
+
let level = "unknown";
|
|
61
|
+
try {
|
|
62
|
+
const l = await shell("sysctl", ["-n", "kern.memorystatus_vm_pressure_level"]);
|
|
63
|
+
level = l === "4" ? "critical" : l === "2" ? "warning" : "normal";
|
|
64
|
+
} catch {
|
|
65
|
+
/* keep unknown */
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// freePct: `memory_pressure` 명령의 "System-wide memory free percentage"
|
|
69
|
+
let freePct: number | null = null;
|
|
37
70
|
try {
|
|
38
|
-
const
|
|
39
|
-
|
|
71
|
+
const out = await shell("memory_pressure", []);
|
|
72
|
+
const m = out.match(/System-wide memory free percentage:\s*(\d+)%/);
|
|
73
|
+
if (m) freePct = Number(m[1]);
|
|
40
74
|
} catch {
|
|
41
|
-
|
|
75
|
+
/* keep null */
|
|
42
76
|
}
|
|
77
|
+
|
|
78
|
+
return { level, freePct };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function getTotalMemBytes(): Promise<number> {
|
|
82
|
+
try {
|
|
83
|
+
return Number(await shell("sysctl", ["-n", "hw.memsize"]));
|
|
84
|
+
} catch {
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function getVmStatMemory(): Promise<SystemHealthMemory> {
|
|
90
|
+
const [out, totalFromSysctl] = await Promise.all([shell("vm_stat", []), getTotalMemBytes()]);
|
|
91
|
+
const extract = (label: string): number => {
|
|
92
|
+
const m = out.match(new RegExp(`${label.replace(/\s/g, "\\s")}:\\s+(\\d+)`));
|
|
93
|
+
return m ? Number(m[1]) : 0;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// page size를 헤더에서 동적 추출 (Apple Silicon 16384 / Intel 4096)
|
|
97
|
+
const pageSize = Number(out.match(/page size of (\d+) bytes/)?.[1]) || 16384;
|
|
98
|
+
const pagesFree = extract("Pages free");
|
|
99
|
+
const pagesActive = extract("Pages active");
|
|
100
|
+
const pagesInactive = extract("Pages inactive");
|
|
101
|
+
const pagesSpeculative = extract("Pages speculative");
|
|
102
|
+
const pagesWired = extract("Pages wired down");
|
|
103
|
+
const pagesPurgeable = extract("Pages purgeable");
|
|
104
|
+
const pagesCompressor = extract("Pages occupied by compressor");
|
|
105
|
+
|
|
106
|
+
// btop 공식: used = (active + wired). inactive/compressor/purgeable 제외.
|
|
107
|
+
const activeBytes = pagesActive * pageSize;
|
|
108
|
+
const wiredBytes = pagesWired * pageSize;
|
|
109
|
+
const usedBytes = activeBytes + wiredBytes;
|
|
110
|
+
const cacheBytes = (pagesInactive + pagesSpeculative + pagesPurgeable) * pageSize;
|
|
111
|
+
const compressorBytes = pagesCompressor * pageSize;
|
|
112
|
+
// total은 hw.memsize 우선 (page 합산은 부정확). 실패 시 page 합산 폴백.
|
|
113
|
+
const totalBytes =
|
|
114
|
+
totalFromSysctl ||
|
|
115
|
+
(pagesFree +
|
|
116
|
+
pagesActive +
|
|
117
|
+
pagesInactive +
|
|
118
|
+
pagesSpeculative +
|
|
119
|
+
pagesWired +
|
|
120
|
+
pagesPurgeable +
|
|
121
|
+
pagesCompressor) *
|
|
122
|
+
pageSize;
|
|
123
|
+
const availableBytes = Math.max(0, totalBytes - usedBytes);
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
usedBytes,
|
|
127
|
+
cacheBytes,
|
|
128
|
+
compressorBytes,
|
|
129
|
+
availableBytes,
|
|
130
|
+
totalBytes,
|
|
131
|
+
activeBytes,
|
|
132
|
+
wiredBytes,
|
|
133
|
+
};
|
|
43
134
|
}
|
|
44
135
|
|
|
45
136
|
async function getSwapUsage(): Promise<string> {
|
|
@@ -95,19 +186,19 @@ async function getDisk(): Promise<string> {
|
|
|
95
186
|
|
|
96
187
|
export const defaultSystemHealthMcpHost: SystemHealthMcpHost = {
|
|
97
188
|
async readSystemHealth() {
|
|
98
|
-
const [memoryPressure, swap, thermal, disk, processCount] = await Promise.all([
|
|
189
|
+
const [memoryPressure, swap, thermal, disk, processCount, memory] = await Promise.all([
|
|
99
190
|
getMemoryPressure(),
|
|
100
191
|
getSwapUsage(),
|
|
101
192
|
getThermal(),
|
|
102
193
|
getDisk(),
|
|
103
194
|
getProcessCount(),
|
|
195
|
+
getVmStatMemory(),
|
|
104
196
|
]);
|
|
105
197
|
const load = loadavg();
|
|
106
198
|
return {
|
|
107
199
|
cpuLoad: [load[0] ?? 0, load[1] ?? 0, load[2] ?? 0],
|
|
108
200
|
cpuCount: cpus().length,
|
|
109
|
-
|
|
110
|
-
memoryFree: freemem(),
|
|
201
|
+
memory,
|
|
111
202
|
memoryPressure,
|
|
112
203
|
swap,
|
|
113
204
|
disk,
|
|
@@ -126,25 +217,36 @@ export function createSystemHealthMcpServer(
|
|
|
126
217
|
[
|
|
127
218
|
"시스템 상태를 조회합니다.",
|
|
128
219
|
"- CPU 부하 (load average 1/5/15분)",
|
|
129
|
-
"-
|
|
220
|
+
"- 메모리: 앱 실사용(active+wired) / 파일캐시(반환가능) / available / 압력(free%·level)",
|
|
130
221
|
"- 스왑 사용량",
|
|
131
222
|
"- 디스크 사용률 (/)",
|
|
132
223
|
"- 열 상태 (thermal)",
|
|
133
224
|
"- 프로세스 수",
|
|
225
|
+
"",
|
|
226
|
+
"⚠️ Chromium/playwright 등 무거운 프로세스 실행 가능 여부는 '메모리 사용%'가 아니라",
|
|
227
|
+
" 메모리 압력 레벨(normal/warning/critical) + available GB 로 판단할 것.",
|
|
228
|
+
" (파일 캐시는 압박 시 즉시 반환되므로 used%에 겁먹지 말 것)",
|
|
134
229
|
].join("\n"),
|
|
135
230
|
{},
|
|
136
231
|
async () => {
|
|
137
232
|
const snapshot = await host.readSystemHealth();
|
|
138
|
-
const
|
|
139
|
-
const
|
|
233
|
+
const { memory } = snapshot;
|
|
234
|
+
const usedPct =
|
|
235
|
+
memory.totalBytes > 0 ? ((memory.usedBytes / memory.totalBytes) * 100).toFixed(1) : "0.0";
|
|
140
236
|
const [load1, load5, load15] = snapshot.cpuLoad;
|
|
237
|
+
const pressureStr =
|
|
238
|
+
snapshot.memoryPressure.freePct !== null
|
|
239
|
+
? `${snapshot.memoryPressure.level} (free ${snapshot.memoryPressure.freePct}%)`
|
|
240
|
+
: snapshot.memoryPressure.level;
|
|
141
241
|
return mcpOk(
|
|
142
242
|
[
|
|
143
243
|
"시스템 상태",
|
|
144
244
|
"",
|
|
145
245
|
`CPU 부하: ${load1.toFixed(2)} / ${load5.toFixed(2)} / ${load15.toFixed(2)} (1/5/15분, 코어 ${snapshot.cpuCount}개)`,
|
|
146
|
-
|
|
147
|
-
|
|
246
|
+
`메모리 실사용: ${fmtBytes(memory.usedBytes)} / ${fmtBytes(memory.totalBytes)} (${usedPct}%) available: ${fmtBytes(memory.availableBytes)}`,
|
|
247
|
+
` (active ${fmtBytes(memory.activeBytes)} + wired ${fmtBytes(memory.wiredBytes)})`,
|
|
248
|
+
`파일 캐시: ${fmtBytes(memory.cacheBytes)} (압박 시 반환 가능) | 압축 ${fmtBytes(memory.compressorBytes)}`,
|
|
249
|
+
`메모리 압력: ${pressureStr}`,
|
|
148
250
|
`스왑: ${snapshot.swap}`,
|
|
149
251
|
`디스크(/): ${snapshot.disk}`,
|
|
150
252
|
`열 상태: ${snapshot.thermal}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const NEGOTIUM_VERSION = "0.6.
|
|
1
|
+
export const NEGOTIUM_VERSION = "0.6.9";
|
|
@@ -1,10 +1,30 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
export interface SystemHealthMemory {
|
|
3
|
+
/** 앱 실사용 (btop 방식, 회수 불가) = active + wired */
|
|
4
|
+
usedBytes: number;
|
|
5
|
+
/** 파일 캐시/버퍼 등 압박 시 즉시 반환 가능 = inactive + speculative + purgeable */
|
|
6
|
+
cacheBytes: number;
|
|
7
|
+
/** 압축된 익명 메모리 (스왑 압박 시 지표) */
|
|
8
|
+
compressorBytes: number;
|
|
9
|
+
/** available = total - used(active+wired) */
|
|
10
|
+
availableBytes: number;
|
|
11
|
+
totalBytes: number;
|
|
12
|
+
/** active만 (breakdown 표시용) */
|
|
13
|
+
activeBytes: number;
|
|
14
|
+
/** wired만 (breakdown 표시용) */
|
|
15
|
+
wiredBytes: number;
|
|
16
|
+
}
|
|
17
|
+
export interface SystemHealthMemoryPressure {
|
|
18
|
+
/** normal / warning / critical / unknown */
|
|
19
|
+
level: string;
|
|
20
|
+
/** macOS 공식 "System-wide memory free percentage" (0~100), 없으면 null */
|
|
21
|
+
freePct: number | null;
|
|
22
|
+
}
|
|
2
23
|
export interface SystemHealthSnapshot {
|
|
3
24
|
cpuLoad: [number, number, number];
|
|
4
25
|
cpuCount: number;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
memoryPressure: string;
|
|
26
|
+
memory: SystemHealthMemory;
|
|
27
|
+
memoryPressure: SystemHealthMemoryPressure;
|
|
8
28
|
swap: string;
|
|
9
29
|
disk: string;
|
|
10
30
|
thermal: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const NEGOTIUM_VERSION = "0.6.
|
|
1
|
+
export declare const NEGOTIUM_VERSION = "0.6.9";
|