@covibes/zeroshot 5.4.0 → 5.4.1

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 (136) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +8 -465
  3. package/cli/index.js +101 -5231
  4. package/package.json +16 -130
  5. package/CHANGELOG.md +0 -537
  6. package/cli/commands/providers.js +0 -149
  7. package/cli/lib/first-run.js +0 -211
  8. package/cli/lib/update-checker.js +0 -281
  9. package/cli/message-formatter-utils.js +0 -75
  10. package/cli/message-formatters-normal.js +0 -275
  11. package/cli/message-formatters-watch.js +0 -181
  12. package/cluster-templates/base-templates/debug-workflow.json +0 -375
  13. package/cluster-templates/base-templates/full-workflow.json +0 -581
  14. package/cluster-templates/base-templates/single-worker.json +0 -63
  15. package/cluster-templates/base-templates/worker-validator.json +0 -208
  16. package/cluster-templates/conductor-bootstrap.json +0 -124
  17. package/docker/zeroshot-cluster/Dockerfile +0 -152
  18. package/docker/zeroshot-cluster/pre-baked-deps.json +0 -28
  19. package/lib/completion.js +0 -174
  20. package/lib/docker-config.js +0 -220
  21. package/lib/git-remote-utils.js +0 -165
  22. package/lib/id-detector.js +0 -56
  23. package/lib/provider-defaults.js +0 -62
  24. package/lib/provider-detection.js +0 -59
  25. package/lib/provider-names.js +0 -57
  26. package/lib/settings/claude-auth.js +0 -78
  27. package/lib/settings.js +0 -503
  28. package/lib/stream-json-parser.js +0 -10
  29. package/scripts/fix-node-pty-permissions.js +0 -75
  30. package/scripts/record-demo.sh +0 -279
  31. package/scripts/setup-merge-queue.sh +0 -170
  32. package/scripts/test-install.sh +0 -40
  33. package/scripts/validate-templates.js +0 -100
  34. package/src/agent/agent-config.js +0 -246
  35. package/src/agent/agent-context-builder.js +0 -444
  36. package/src/agent/agent-hook-executor.js +0 -599
  37. package/src/agent/agent-lifecycle.js +0 -743
  38. package/src/agent/agent-stuck-detector.js +0 -256
  39. package/src/agent/agent-task-executor.js +0 -1690
  40. package/src/agent/agent-trigger-evaluator.js +0 -67
  41. package/src/agent/output-extraction.js +0 -217
  42. package/src/agent/output-reformatter.js +0 -175
  43. package/src/agent/schema-utils.js +0 -146
  44. package/src/agent-wrapper.js +0 -579
  45. package/src/agents/git-pusher-template.js +0 -285
  46. package/src/attach/attach-client.js +0 -438
  47. package/src/attach/attach-server.js +0 -543
  48. package/src/attach/index.js +0 -35
  49. package/src/attach/protocol.js +0 -220
  50. package/src/attach/ring-buffer.js +0 -121
  51. package/src/attach/socket-discovery.js +0 -267
  52. package/src/claude-task-runner.js +0 -574
  53. package/src/config-router.js +0 -80
  54. package/src/config-validator.js +0 -1925
  55. package/src/copy-worker.js +0 -43
  56. package/src/input-helpers.js +0 -65
  57. package/src/isolation-manager.js +0 -1471
  58. package/src/issue-providers/README.md +0 -305
  59. package/src/issue-providers/azure-devops-provider.js +0 -273
  60. package/src/issue-providers/base-provider.js +0 -232
  61. package/src/issue-providers/github-provider.js +0 -179
  62. package/src/issue-providers/gitlab-provider.js +0 -241
  63. package/src/issue-providers/index.js +0 -196
  64. package/src/issue-providers/jira-provider.js +0 -239
  65. package/src/ledger.js +0 -631
  66. package/src/lib/safe-exec.js +0 -88
  67. package/src/logic-engine.js +0 -223
  68. package/src/message-bus-bridge.js +0 -139
  69. package/src/message-bus.js +0 -249
  70. package/src/name-generator.js +0 -232
  71. package/src/orchestrator.js +0 -2815
  72. package/src/preflight.js +0 -639
  73. package/src/process-metrics.js +0 -608
  74. package/src/providers/anthropic/cli-builder.js +0 -73
  75. package/src/providers/anthropic/index.js +0 -204
  76. package/src/providers/anthropic/models.js +0 -23
  77. package/src/providers/anthropic/output-parser.js +0 -177
  78. package/src/providers/base-provider.js +0 -251
  79. package/src/providers/capabilities.js +0 -60
  80. package/src/providers/google/cli-builder.js +0 -55
  81. package/src/providers/google/index.js +0 -116
  82. package/src/providers/google/models.js +0 -24
  83. package/src/providers/google/output-parser.js +0 -101
  84. package/src/providers/index.js +0 -91
  85. package/src/providers/openai/cli-builder.js +0 -133
  86. package/src/providers/openai/index.js +0 -136
  87. package/src/providers/openai/models.js +0 -21
  88. package/src/providers/openai/output-parser.js +0 -143
  89. package/src/providers/opencode/cli-builder.js +0 -42
  90. package/src/providers/opencode/index.js +0 -103
  91. package/src/providers/opencode/models.js +0 -55
  92. package/src/providers/opencode/output-parser.js +0 -122
  93. package/src/schemas/sub-cluster.js +0 -185
  94. package/src/status-footer.js +0 -1026
  95. package/src/sub-cluster-wrapper.js +0 -601
  96. package/src/task-runner.js +0 -30
  97. package/src/template-resolver.js +0 -372
  98. package/src/tui/CHANGES.txt +0 -133
  99. package/src/tui/LAYOUT.md +0 -261
  100. package/src/tui/README.txt +0 -192
  101. package/src/tui/TWO-LEVEL-NAVIGATION.md +0 -186
  102. package/src/tui/data-poller.js +0 -349
  103. package/src/tui/demo.js +0 -208
  104. package/src/tui/formatters.js +0 -129
  105. package/src/tui/index.js +0 -193
  106. package/src/tui/keybindings.js +0 -324
  107. package/src/tui/layout.js +0 -334
  108. package/src/tui/renderer.js +0 -184
  109. package/task-lib/attachable-watcher.js +0 -309
  110. package/task-lib/claude-recovery.js +0 -156
  111. package/task-lib/commands/clean.js +0 -50
  112. package/task-lib/commands/episodes.js +0 -105
  113. package/task-lib/commands/get-log-path.js +0 -23
  114. package/task-lib/commands/kill.js +0 -32
  115. package/task-lib/commands/list.js +0 -105
  116. package/task-lib/commands/logs.js +0 -453
  117. package/task-lib/commands/resume.js +0 -42
  118. package/task-lib/commands/run.js +0 -57
  119. package/task-lib/commands/schedule.js +0 -105
  120. package/task-lib/commands/scheduler-cmd.js +0 -96
  121. package/task-lib/commands/schedules.js +0 -148
  122. package/task-lib/commands/status.js +0 -44
  123. package/task-lib/commands/unschedule.js +0 -16
  124. package/task-lib/completion.js +0 -9
  125. package/task-lib/config.js +0 -8
  126. package/task-lib/name-generator.js +0 -230
  127. package/task-lib/package.json +0 -3
  128. package/task-lib/runner.js +0 -201
  129. package/task-lib/scheduler.js +0 -252
  130. package/task-lib/store.js +0 -529
  131. package/task-lib/tui/formatters.js +0 -215
  132. package/task-lib/tui/index.js +0 -197
  133. package/task-lib/tui/layout.js +0 -111
  134. package/task-lib/tui/renderer.js +0 -129
  135. package/task-lib/tui.js +0 -425
  136. package/task-lib/watcher.js +0 -226
@@ -1,608 +0,0 @@
1
- /**
2
- * ProcessMetrics - Cross-platform real-time process monitoring
3
- *
4
- * Provides:
5
- * - CPU usage (percent)
6
- * - Memory usage (MB)
7
- * - Network I/O (bytes/sec)
8
- * - Process state (running, sleeping, etc.)
9
- * - Child process aggregation
10
- *
11
- * Supports:
12
- * - Linux: /proc filesystem + ss
13
- * - macOS: ps + lsof
14
- */
15
-
16
- const { execSync } = require('./lib/safe-exec'); // Enforces timeouts
17
- const fs = require('fs');
18
-
19
- const PLATFORM = process.platform;
20
-
21
- /**
22
- * Escape a string for safe use in shell commands
23
- * Prevents shell injection when passing dynamic values to execSync with shell: true
24
- * @param {string} str - String to escape
25
- * @returns {string} Shell-escaped string
26
- */
27
- function escapeShell(str) {
28
- // Replace single quotes with escaped version and wrap in single quotes
29
- // This is the safest approach for shell escaping
30
- return `'${str.replace(/'/g, "'\\''")}'`;
31
- }
32
-
33
- /**
34
- * @typedef {Object} ProcessMetrics
35
- * @property {number} pid - Process ID
36
- * @property {boolean} exists - Whether process exists
37
- * @property {number} cpuPercent - CPU usage (0-100)
38
- * @property {number} memoryMB - Memory usage in MB
39
- * @property {string} state - Process state (R=running, S=sleeping, etc.)
40
- * @property {number} threads - Thread count
41
- * @property {Object} network - Network activity
42
- * @property {number} network.established - Established connections
43
- * @property {boolean} network.hasActivity - Has data in flight
44
- * @property {number} network.sendQueueBytes - Bytes in send queue
45
- * @property {number} network.recvQueueBytes - Bytes in receive queue
46
- * @property {number} childCount - Number of child processes
47
- * @property {number} timestamp - Measurement timestamp
48
- */
49
-
50
- /**
51
- * Get all child PIDs for a process (recursive)
52
- * @param {number} pid - Parent process ID
53
- * @returns {number[]} Array of child PIDs
54
- */
55
- function getChildPids(pid) {
56
- const children = [];
57
-
58
- try {
59
- const childPids =
60
- PLATFORM === 'darwin' ? collectDarwinChildPids(pid) : collectLinuxChildPids(pid);
61
- children.push(...childPids);
62
-
63
- // Recursively get grandchildren
64
- for (const childPid of childPids) {
65
- children.push(...getChildPids(childPid));
66
- }
67
- } catch {
68
- // Ignore errors (process may have exited)
69
- }
70
-
71
- return [...new Set(children)]; // Dedupe
72
- }
73
-
74
- function collectDarwinChildPids(pid) {
75
- const output = execSync(`pgrep -P ${escapeShell(String(pid))} 2>/dev/null`, {
76
- encoding: 'utf8',
77
- timeout: 2000,
78
- });
79
-
80
- return output.trim().split('\n').filter(Boolean).map(Number);
81
- }
82
-
83
- function collectLinuxChildPids(pid) {
84
- const taskPath = `/proc/${pid}/task`;
85
- if (!fs.existsSync(taskPath)) {
86
- return [];
87
- }
88
-
89
- const tids = fs.readdirSync(taskPath);
90
- const childPids = [];
91
-
92
- for (const tid of tids) {
93
- const childrenPath = `/proc/${pid}/task/${tid}/children`;
94
- childPids.push(...readChildPidFile(childrenPath));
95
- }
96
-
97
- return childPids;
98
- }
99
-
100
- function readChildPidFile(childrenPath) {
101
- if (!fs.existsSync(childrenPath)) {
102
- return [];
103
- }
104
-
105
- const raw = fs.readFileSync(childrenPath, 'utf8').trim();
106
- if (!raw) {
107
- return [];
108
- }
109
-
110
- return raw.split(/\s+/).filter(Boolean).map(Number);
111
- }
112
-
113
- /**
114
- * Get metrics for a single process (Linux)
115
- * @param {number} pid - Process ID
116
- * @returns {Object|null} Metrics or null if process doesn't exist
117
- */
118
- function getProcessMetricsLinux(pid) {
119
- try {
120
- const statPath = `/proc/${pid}/stat`;
121
- if (!fs.existsSync(statPath)) {
122
- return null;
123
- }
124
-
125
- const stat = fs.readFileSync(statPath, 'utf8');
126
- const parts = stat.split(' ');
127
-
128
- // state is field 3 (index 2)
129
- const state = parts[2];
130
-
131
- // utime (14) + stime (15) = CPU ticks
132
- const utime = parseInt(parts[13], 10);
133
- const stime = parseInt(parts[14], 10);
134
- const cpuTicks = utime + stime;
135
-
136
- // Read status for memory and threads
137
- const status = fs.readFileSync(`/proc/${pid}/status`, 'utf8');
138
- const vmRss = status.match(/VmRSS:\s+(\d+)/)?.[1] || '0';
139
- const threads = status.match(/Threads:\s+(\d+)/)?.[1] || '1';
140
-
141
- return {
142
- pid,
143
- exists: true,
144
- state,
145
- cpuTicks,
146
- memoryKB: parseInt(vmRss, 10),
147
- threads: parseInt(threads, 10),
148
- };
149
- } catch {
150
- return null;
151
- }
152
- }
153
-
154
- /**
155
- * Get metrics for a single process (macOS)
156
- * @param {number} pid - Process ID
157
- * @returns {Object|null} Metrics or null if process doesn't exist
158
- */
159
- function getProcessMetricsDarwin(pid) {
160
- try {
161
- // ps -p PID -o %cpu=,rss=,state=
162
- const output = execSync(`ps -p ${escapeShell(String(pid))} -o %cpu=,rss=,state= 2>/dev/null`, {
163
- encoding: 'utf8',
164
- timeout: 2000,
165
- });
166
-
167
- if (!output.trim()) {
168
- return null;
169
- }
170
-
171
- const parts = output.trim().split(/\s+/);
172
- const cpuPercent = parseFloat(parts[0]) || 0;
173
- const rssKB = parseInt(parts[1], 10) || 0;
174
- const state = parts[2]?.[0] || 'S'; // First char (R, S, etc.)
175
-
176
- return {
177
- pid,
178
- exists: true,
179
- state,
180
- cpuPercent, // macOS ps gives us percent directly
181
- memoryKB: rssKB,
182
- threads: 1, // ps doesn't give thread count easily
183
- };
184
- } catch {
185
- return null;
186
- }
187
- }
188
-
189
- /**
190
- * Get network state for a process (Linux)
191
- * Uses ss -tip to get extended TCP info including cumulative bytes sent/received
192
- * @param {number} pid - Process ID
193
- * @returns {Object} Network state
194
- */
195
- function getNetworkStateLinux(pid) {
196
- const result = {
197
- established: 0,
198
- hasActivity: false,
199
- sendQueueBytes: 0,
200
- recvQueueBytes: 0,
201
- bytesSent: 0, // Cumulative bytes sent across all sockets
202
- bytesReceived: 0, // Cumulative bytes received across all sockets
203
- };
204
-
205
- try {
206
- // Use ss -tip to get extended TCP info with bytes_sent/bytes_received
207
- // -t = TCP only, -i = show internal TCP info, -p = show process
208
- const output = execSync(
209
- `ss -tip 2>/dev/null | grep -A1 "pid=${escapeShell(String(pid))}," || true`,
210
- {
211
- encoding: 'utf8',
212
- timeout: 3000,
213
- }
214
- );
215
-
216
- if (!output.trim()) {
217
- return result;
218
- }
219
-
220
- const lines = output.trim().split('\n');
221
-
222
- for (let i = 0; i < lines.length; i++) {
223
- const line = lines[i];
224
-
225
- // Parse socket line: State Recv-Q Send-Q Local:Port Peer:Port Process
226
- const match = line.match(/^(\S+)\s+(\d+)\s+(\d+)\s+/);
227
- if (match) {
228
- const state = match[1];
229
- const recvQ = parseInt(match[2], 10);
230
- const sendQ = parseInt(match[3], 10);
231
-
232
- if (state === 'ESTAB') {
233
- result.established++;
234
- }
235
-
236
- result.recvQueueBytes += recvQ;
237
- result.sendQueueBytes += sendQ;
238
-
239
- if (recvQ > 0 || sendQ > 0) {
240
- result.hasActivity = true;
241
- }
242
- }
243
-
244
- // Parse extended TCP info line (follows socket line)
245
- // Contains: bytes_sent:N bytes_received:N (and other metrics)
246
- const bytesSentMatch = line.match(/bytes_sent:(\d+)/);
247
- const bytesReceivedMatch = line.match(/bytes_received:(\d+)/);
248
-
249
- if (bytesSentMatch) {
250
- result.bytesSent += parseInt(bytesSentMatch[1], 10);
251
- result.hasActivity = true;
252
- }
253
- if (bytesReceivedMatch) {
254
- result.bytesReceived += parseInt(bytesReceivedMatch[1], 10);
255
- result.hasActivity = true;
256
- }
257
- }
258
- } catch {
259
- // Ignore errors
260
- }
261
-
262
- return result;
263
- }
264
-
265
- /**
266
- * Get network state for a process (macOS)
267
- * Note: macOS doesn't expose per-socket byte counts like Linux's ss -tip
268
- * We return 0 for bytesSent/bytesReceived (not available without dtrace/nettop)
269
- * @param {number} pid - Process ID
270
- * @returns {Object} Network state
271
- */
272
- function getNetworkStateDarwin(pid) {
273
- const result = {
274
- established: 0,
275
- hasActivity: false,
276
- sendQueueBytes: 0,
277
- recvQueueBytes: 0,
278
- bytesSent: 0, // Not available on macOS without root/dtrace
279
- bytesReceived: 0, // Not available on macOS without root/dtrace
280
- };
281
-
282
- try {
283
- // lsof -i -n -P for network connections
284
- const output = execSync(`lsof -i -n -P -a -p ${escapeShell(String(pid))} 2>/dev/null || true`, {
285
- encoding: 'utf8',
286
- timeout: 3000,
287
- });
288
-
289
- if (!output.trim()) {
290
- return result;
291
- }
292
-
293
- const lines = output.trim().split('\n').slice(1); // Skip header
294
-
295
- for (const line of lines) {
296
- const parts = line.split(/\s+/);
297
- // Look for ESTABLISHED connections
298
- if (parts.includes('ESTABLISHED') || parts.some((p) => p.includes('->'))) {
299
- result.established++;
300
- result.hasActivity = true; // lsof doesn't show queue sizes, assume activity
301
- }
302
- }
303
- } catch {
304
- // Ignore errors
305
- }
306
-
307
- return result;
308
- }
309
-
310
- /**
311
- * Get real-time metrics for a process and its children
312
- * @param {number} pid - Process ID
313
- * @param {Object} [options] - Options
314
- * @param {number} [options.samplePeriodMs=1000] - Sample period for rate calculations (Linux only)
315
- * @returns {Promise<ProcessMetrics>}
316
- */
317
- function getProcessMetrics(pid, options = {}) {
318
- const samplePeriodMs = options.samplePeriodMs || 1000;
319
-
320
- if (PLATFORM === 'darwin') {
321
- return getProcessMetricsDarwinAggregated(pid);
322
- }
323
-
324
- return getProcessMetricsLinuxAggregated(pid, samplePeriodMs);
325
- }
326
-
327
- /**
328
- * Get aggregated metrics for process tree (Linux)
329
- * @param {number} pid - Root process ID
330
- * @param {number} samplePeriodMs - Sample period for CPU calculation
331
- * @returns {Promise<ProcessMetrics>}
332
- */
333
- async function getProcessMetricsLinuxAggregated(pid, samplePeriodMs) {
334
- // Get initial CPU sample
335
- const allPids = [pid, ...getChildPids(pid)];
336
- const t0Metrics = {};
337
-
338
- for (const p of allPids) {
339
- const m = getProcessMetricsLinux(p);
340
- if (m) t0Metrics[p] = m;
341
- }
342
-
343
- if (Object.keys(t0Metrics).length === 0) {
344
- return {
345
- pid,
346
- exists: false,
347
- cpuPercent: 0,
348
- memoryMB: 0,
349
- state: 'X',
350
- threads: 0,
351
- network: {
352
- established: 0,
353
- hasActivity: false,
354
- sendQueueBytes: 0,
355
- recvQueueBytes: 0,
356
- bytesSent: 0,
357
- bytesReceived: 0,
358
- },
359
- childCount: 0,
360
- timestamp: Date.now(),
361
- };
362
- }
363
-
364
- // Wait for sample period
365
- await new Promise((r) => setTimeout(r, samplePeriodMs));
366
-
367
- // Get second CPU sample
368
- const t1Metrics = {};
369
- const currentPids = [pid, ...getChildPids(pid)];
370
-
371
- for (const p of currentPids) {
372
- const m = getProcessMetricsLinux(p);
373
- if (m) t1Metrics[p] = m;
374
- }
375
-
376
- // Calculate aggregated metrics
377
- let totalCpuTicksDelta = 0;
378
- let totalMemoryKB = 0;
379
- let totalThreads = 0;
380
- let rootState = 'S';
381
-
382
- for (const p of Object.keys(t1Metrics)) {
383
- const t1 = t1Metrics[p];
384
- const t0 = t0Metrics[p];
385
-
386
- if (t0 && t1) {
387
- totalCpuTicksDelta += t1.cpuTicks - t0.cpuTicks;
388
- }
389
-
390
- totalMemoryKB += t1.memoryKB;
391
- totalThreads += t1.threads;
392
-
393
- if (p === String(pid)) {
394
- rootState = t1.state;
395
- }
396
- }
397
-
398
- // Calculate CPU percent
399
- const clockTicks = 100; // Usually 100 on Linux
400
- const cpuSeconds = totalCpuTicksDelta / clockTicks;
401
- const sampleSeconds = samplePeriodMs / 1000;
402
- const rawCpuPercent = (cpuSeconds / sampleSeconds) * 100;
403
-
404
- // Normalize to per-core average (0-100% range)
405
- const cpuCores = require('os').cpus().length;
406
- const cpuPercent = Math.min(100, rawCpuPercent / cpuCores);
407
-
408
- // Get network state for all processes
409
- let network = {
410
- established: 0,
411
- hasActivity: false,
412
- sendQueueBytes: 0,
413
- recvQueueBytes: 0,
414
- bytesSent: 0,
415
- bytesReceived: 0,
416
- };
417
- for (const p of Object.keys(t1Metrics)) {
418
- const netState = getNetworkStateLinux(parseInt(p, 10));
419
- network.established += netState.established;
420
- network.sendQueueBytes += netState.sendQueueBytes;
421
- network.recvQueueBytes += netState.recvQueueBytes;
422
- network.bytesSent += netState.bytesSent;
423
- network.bytesReceived += netState.bytesReceived;
424
- if (netState.hasActivity) network.hasActivity = true;
425
- }
426
-
427
- return {
428
- pid,
429
- exists: true,
430
- cpuPercent: parseFloat(cpuPercent.toFixed(1)),
431
- memoryMB: parseFloat((totalMemoryKB / 1024).toFixed(1)),
432
- state: rootState,
433
- threads: totalThreads,
434
- network,
435
- childCount: Object.keys(t1Metrics).length - 1,
436
- timestamp: Date.now(),
437
- };
438
- }
439
-
440
- /**
441
- * Get aggregated metrics for process tree (macOS)
442
- * @param {number} pid - Root process ID
443
- * @returns {Promise<ProcessMetrics>}
444
- */
445
- function getProcessMetricsDarwinAggregated(pid) {
446
- const allPids = [pid, ...getChildPids(pid)];
447
- let totalCpuPercent = 0;
448
- let totalMemoryKB = 0;
449
- let totalThreads = 0;
450
- let rootState = 'S';
451
- let existsCount = 0;
452
-
453
- for (const p of allPids) {
454
- const m = getProcessMetricsDarwin(p);
455
- if (m) {
456
- existsCount++;
457
- totalCpuPercent += m.cpuPercent;
458
- totalMemoryKB += m.memoryKB;
459
- totalThreads += m.threads;
460
-
461
- if (p === pid) {
462
- rootState = m.state;
463
- }
464
- }
465
- }
466
-
467
- if (existsCount === 0) {
468
- return {
469
- pid,
470
- exists: false,
471
- cpuPercent: 0,
472
- memoryMB: 0,
473
- state: 'X',
474
- threads: 0,
475
- network: { established: 0, hasActivity: false, sendQueueBytes: 0, recvQueueBytes: 0 },
476
- childCount: 0,
477
- timestamp: Date.now(),
478
- };
479
- }
480
-
481
- // Get network state
482
- let network = {
483
- established: 0,
484
- hasActivity: false,
485
- sendQueueBytes: 0,
486
- recvQueueBytes: 0,
487
- bytesSent: 0,
488
- bytesReceived: 0,
489
- };
490
- for (const p of allPids) {
491
- const netState = getNetworkStateDarwin(p);
492
- network.established += netState.established;
493
- network.bytesSent += netState.bytesSent;
494
- network.bytesReceived += netState.bytesReceived;
495
- if (netState.hasActivity) network.hasActivity = true;
496
- }
497
-
498
- // Normalize to per-core average (0-100% range)
499
- const cpuCores = require('os').cpus().length;
500
- const normalizedCpu = Math.min(100, totalCpuPercent / cpuCores);
501
-
502
- return {
503
- pid,
504
- exists: true,
505
- cpuPercent: parseFloat(normalizedCpu.toFixed(1)),
506
- memoryMB: parseFloat((totalMemoryKB / 1024).toFixed(1)),
507
- state: rootState,
508
- threads: totalThreads,
509
- network,
510
- childCount: existsCount - 1,
511
- timestamp: Date.now(),
512
- };
513
- }
514
-
515
- /**
516
- * Format metrics for display
517
- * @param {ProcessMetrics} metrics
518
- * @returns {string} Formatted string
519
- */
520
- function formatMetrics(metrics) {
521
- if (!metrics.exists) {
522
- return '(process exited)';
523
- }
524
-
525
- const parts = [];
526
-
527
- // CPU
528
- parts.push(`CPU: ${metrics.cpuPercent}%`);
529
-
530
- // Memory
531
- parts.push(`Mem: ${metrics.memoryMB}MB`);
532
-
533
- // Network
534
- if (metrics.network.established > 0) {
535
- parts.push(`Net: ${metrics.network.established} conn`);
536
- if (metrics.network.hasActivity) {
537
- parts.push('↕');
538
- }
539
- }
540
-
541
- // Children
542
- if (metrics.childCount > 0) {
543
- parts.push(`+${metrics.childCount} child`);
544
- }
545
-
546
- return parts.join(' │ ');
547
- }
548
-
549
- /**
550
- * Get state icon for process state
551
- * @param {string} state - Process state char
552
- * @returns {string} Icon
553
- */
554
- function getStateIcon(state) {
555
- switch (state) {
556
- case 'R':
557
- return '🟢'; // Running
558
- case 'S':
559
- return '🔵'; // Sleeping
560
- case 'D':
561
- return '🟡'; // Disk wait
562
- case 'Z':
563
- return '💀'; // Zombie
564
- case 'T':
565
- return '⏸️'; // Stopped
566
- case 'X':
567
- return '❌'; // Dead
568
- default:
569
- return '⚪';
570
- }
571
- }
572
-
573
- /**
574
- * Check if platform is supported for full metrics
575
- * @returns {boolean}
576
- */
577
- function isPlatformSupported() {
578
- return PLATFORM === 'linux' || PLATFORM === 'darwin';
579
- }
580
-
581
- /**
582
- * Get platform-specific metrics provider info
583
- * @returns {Object}
584
- */
585
- function getPlatformInfo() {
586
- return {
587
- platform: PLATFORM,
588
- supported: isPlatformSupported(),
589
- cpuSource: PLATFORM === 'linux' ? '/proc/stat' : 'ps',
590
- memorySource: PLATFORM === 'linux' ? '/proc/status' : 'ps',
591
- networkSource: PLATFORM === 'linux' ? 'ss' : 'lsof',
592
- ioSupported: PLATFORM === 'linux', // I/O only on Linux
593
- };
594
- }
595
-
596
- module.exports = {
597
- getProcessMetrics,
598
- getChildPids,
599
- formatMetrics,
600
- getStateIcon,
601
- isPlatformSupported,
602
- getPlatformInfo,
603
- // Export internal functions for testing
604
- getProcessMetricsLinux,
605
- getProcessMetricsDarwin,
606
- getNetworkStateLinux,
607
- getNetworkStateDarwin,
608
- };
@@ -1,73 +0,0 @@
1
- function buildCommand(context, options = {}, commandConfig = {}) {
2
- const {
3
- modelSpec,
4
- outputFormat,
5
- jsonSchema,
6
- autoApprove,
7
- cliFeatures = {},
8
- authEnv = {},
9
- } = options;
10
-
11
- const command = commandConfig.command || 'claude';
12
- const extraArgs = commandConfig.args || [];
13
- const args = [...extraArgs, '--print', '--input-format', 'text'];
14
-
15
- addOutputFormatArgs(args, outputFormat, cliFeatures);
16
- addStreamJsonArgs(args, outputFormat, cliFeatures);
17
- addJsonSchemaArgs(args, outputFormat, jsonSchema, cliFeatures);
18
- addModelArgs(args, modelSpec, cliFeatures);
19
- addAutoApproveArgs(args, autoApprove, cliFeatures);
20
-
21
- args.push(context);
22
-
23
- return {
24
- binary: command,
25
- args,
26
- env: authEnv,
27
- };
28
- }
29
-
30
- function addOutputFormatArgs(args, outputFormat, cliFeatures) {
31
- if (!outputFormat || cliFeatures.supportsOutputFormat === false) {
32
- return;
33
- }
34
- args.push('--output-format', outputFormat);
35
- }
36
-
37
- function addStreamJsonArgs(args, outputFormat, cliFeatures) {
38
- if (outputFormat !== 'stream-json') {
39
- return;
40
- }
41
- if (cliFeatures.supportsVerbose !== false) {
42
- args.push('--verbose');
43
- }
44
- if (cliFeatures.supportsIncludePartials !== false) {
45
- args.push('--include-partial-messages');
46
- }
47
- }
48
-
49
- function addJsonSchemaArgs(args, outputFormat, jsonSchema, cliFeatures) {
50
- if (!jsonSchema || outputFormat !== 'json' || cliFeatures.supportsJsonSchema === false) {
51
- return;
52
- }
53
- const schemaString = typeof jsonSchema === 'string' ? jsonSchema : JSON.stringify(jsonSchema);
54
- args.push('--json-schema', schemaString);
55
- }
56
-
57
- function addModelArgs(args, modelSpec, cliFeatures) {
58
- if (!modelSpec?.model || cliFeatures.supportsModel === false) {
59
- return;
60
- }
61
- args.push('--model', modelSpec.model);
62
- }
63
-
64
- function addAutoApproveArgs(args, autoApprove, cliFeatures) {
65
- if (!autoApprove || cliFeatures.supportsAutoApprove === false) {
66
- return;
67
- }
68
- args.push('--dangerously-skip-permissions');
69
- }
70
-
71
- module.exports = {
72
- buildCommand,
73
- };