@phnx-labs/agents-cli 1.21.3 → 1.22.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/CHANGELOG.md +67 -0
- package/README.md +32 -3
- package/dist/bin/agents +0 -0
- package/dist/commands/computer-actions.js +1 -0
- package/dist/commands/exec.d.ts +27 -0
- package/dist/commands/exec.js +123 -6
- package/dist/commands/models.js +36 -1
- package/dist/commands/projects.js +22 -2
- package/dist/commands/sessions-backfill.d.ts +32 -0
- package/dist/commands/sessions-backfill.js +186 -0
- package/dist/commands/sessions.d.ts +17 -1
- package/dist/commands/sessions.js +317 -18
- package/dist/commands/teams.js +1 -1
- package/dist/commands/worktree.d.ts +3 -3
- package/dist/commands/worktree.js +35 -4
- package/dist/lib/daemon.d.ts +5 -1
- package/dist/lib/daemon.js +63 -14
- package/dist/lib/devices/resolve-target.d.ts +6 -0
- package/dist/lib/devices/resolve-target.js +9 -3
- package/dist/lib/exec.js +39 -8
- package/dist/lib/hosts/dispatch.d.ts +12 -0
- package/dist/lib/hosts/dispatch.js +23 -6
- package/dist/lib/hosts/reconnect.d.ts +38 -0
- package/dist/lib/hosts/reconnect.js +85 -4
- package/dist/lib/hosts/run-target.js +14 -2
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/model-tiers.d.ts +54 -0
- package/dist/lib/model-tiers.js +229 -0
- package/dist/lib/models.d.ts +3 -0
- package/dist/lib/models.js +44 -7
- package/dist/lib/pricing/prices.json +16 -1
- package/dist/lib/project-focus.d.ts +42 -0
- package/dist/lib/project-focus.js +80 -0
- package/dist/lib/project-schedule.d.ts +75 -0
- package/dist/lib/project-schedule.js +110 -0
- package/dist/lib/redact.d.ts +2 -0
- package/dist/lib/redact.js +22 -0
- package/dist/lib/remote-agents-json.d.ts +2 -0
- package/dist/lib/remote-agents-json.js +3 -3
- package/dist/lib/rotate.d.ts +84 -1
- package/dist/lib/rotate.js +155 -5
- package/dist/lib/runner.d.ts +4 -2
- package/dist/lib/runner.js +13 -4
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/session/bash-command.js +60 -9
- package/dist/lib/session/db.d.ts +7 -1
- package/dist/lib/session/db.js +301 -32
- package/dist/lib/session/discover.d.ts +40 -7
- package/dist/lib/session/discover.js +144 -83
- package/dist/lib/session/parse.d.ts +8 -1
- package/dist/lib/session/parse.js +83 -32
- package/dist/lib/session/remote-list.d.ts +71 -0
- package/dist/lib/session/remote-list.js +410 -2
- package/dist/lib/session/shell-programs.d.ts +15 -0
- package/dist/lib/session/shell-programs.js +359 -0
- package/dist/lib/session/tool-calls.d.ts +88 -0
- package/dist/lib/session/tool-calls.js +612 -0
- package/dist/lib/session/tool-index.d.ts +100 -0
- package/dist/lib/session/tool-index.js +773 -0
- package/dist/lib/session/tool-store.d.ts +15 -0
- package/dist/lib/session/tool-store.js +198 -0
- package/dist/lib/session/types.d.ts +7 -0
- package/dist/lib/state.d.ts +10 -1
- package/dist/lib/state.js +11 -2
- package/dist/lib/teams/remoteWorktree.d.ts +3 -4
- package/dist/lib/teams/remoteWorktree.js +3 -4
- package/dist/lib/teams/worktree.d.ts +11 -1
- package/dist/lib/teams/worktree.js +42 -4
- package/dist/lib/types.d.ts +17 -0
- package/dist/lib/types.js +17 -0
- package/package.json +3 -1
|
@@ -7,9 +7,11 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import * as fs from 'fs';
|
|
9
9
|
import { truncate } from '../format.js';
|
|
10
|
+
import { sanitizeForTerminal } from '../redact.js';
|
|
10
11
|
import * as path from 'path';
|
|
11
12
|
import Database from '../sqlite.js';
|
|
12
13
|
import { isSyntheticUserMessage, extractSlashCommandName, extractSlashCommandFromToolInput } from './prompt.js';
|
|
14
|
+
import { structuredToolResult } from './tool-calls.js';
|
|
13
15
|
/**
|
|
14
16
|
* Largest session file we will load into memory. Above this we throw a clean
|
|
15
17
|
* error instead of OOMing or hitting V8's ERR_STRING_TOO_LONG. Aligns with
|
|
@@ -23,12 +25,7 @@ export const SESSION_FILE_MAX_BYTES = 200_000_000;
|
|
|
23
25
|
* carriage return (0x0d). Everything else in the C0/C1 range and every CSI/OSC
|
|
24
26
|
* escape is dropped.
|
|
25
27
|
*/
|
|
26
|
-
|
|
27
|
-
export function sanitizeForTerminal(s) {
|
|
28
|
-
if (typeof s !== 'string' || !s)
|
|
29
|
-
return s;
|
|
30
|
-
return s.replace(TERMINAL_ESCAPE_REGEX, '');
|
|
31
|
-
}
|
|
28
|
+
export { sanitizeForTerminal } from '../redact.js';
|
|
32
29
|
/** Recursively sanitize every string value within a tool-args object. */
|
|
33
30
|
function sanitizeArgsDeep(value) {
|
|
34
31
|
if (typeof value === 'string')
|
|
@@ -373,6 +370,7 @@ export function parseClaudeContent(content) {
|
|
|
373
370
|
agent: 'claude',
|
|
374
371
|
timestamp,
|
|
375
372
|
tool: toolName,
|
|
373
|
+
callId: toolId,
|
|
376
374
|
args: toolInput,
|
|
377
375
|
path: toolInput.file_path || undefined,
|
|
378
376
|
command: toolName === 'Bash' ? toolInput.command : undefined,
|
|
@@ -460,6 +458,7 @@ export function parseClaudeContent(content) {
|
|
|
460
458
|
const toolId = block.tool_use_id;
|
|
461
459
|
const toolInfo = toolId ? toolUseMap.get(toolId) : undefined;
|
|
462
460
|
const isError = block.is_error === true;
|
|
461
|
+
const structured = structuredToolResult(block);
|
|
463
462
|
// Extract output text from tool result
|
|
464
463
|
let output = '';
|
|
465
464
|
if (typeof block.content === 'string') {
|
|
@@ -477,6 +476,11 @@ export function parseClaudeContent(content) {
|
|
|
477
476
|
agent: 'claude',
|
|
478
477
|
timestamp,
|
|
479
478
|
tool: toolInfo?.tool,
|
|
479
|
+
callId: toolId,
|
|
480
|
+
outcome: 'error',
|
|
481
|
+
exitCode: structured.exitCode,
|
|
482
|
+
statusCode: structured.statusCode,
|
|
483
|
+
errorCode: structured.errorCode,
|
|
480
484
|
content: output || 'Tool execution failed',
|
|
481
485
|
});
|
|
482
486
|
}
|
|
@@ -486,7 +490,12 @@ export function parseClaudeContent(content) {
|
|
|
486
490
|
agent: 'claude',
|
|
487
491
|
timestamp,
|
|
488
492
|
tool: toolInfo?.tool,
|
|
493
|
+
callId: toolId,
|
|
489
494
|
success: true,
|
|
495
|
+
outcome: 'ok',
|
|
496
|
+
exitCode: structured.exitCode,
|
|
497
|
+
statusCode: structured.statusCode,
|
|
498
|
+
errorCode: structured.errorCode,
|
|
490
499
|
output: output.length > 500 ? output.slice(0, 497) + '...' : output,
|
|
491
500
|
});
|
|
492
501
|
}
|
|
@@ -656,6 +665,7 @@ export function parseCodexContent(content) {
|
|
|
656
665
|
agent: 'codex',
|
|
657
666
|
timestamp,
|
|
658
667
|
tool: name,
|
|
668
|
+
callId,
|
|
659
669
|
args,
|
|
660
670
|
command: name === 'exec_command' ? (args.command || args.cmd) : undefined,
|
|
661
671
|
path: args.file_path || args.path || undefined,
|
|
@@ -664,14 +674,19 @@ export function parseCodexContent(content) {
|
|
|
664
674
|
else if (ptype === 'function_call_output') {
|
|
665
675
|
const callId = payload.call_id || payload.id;
|
|
666
676
|
const callInfo = callId ? callMap.get(callId) : undefined;
|
|
667
|
-
const
|
|
677
|
+
const result = structuredToolResult(payload.output);
|
|
668
678
|
events.push({
|
|
669
679
|
type: 'tool_result',
|
|
670
680
|
agent: 'codex',
|
|
671
681
|
timestamp,
|
|
672
682
|
tool: callInfo?.name,
|
|
673
|
-
|
|
674
|
-
|
|
683
|
+
callId,
|
|
684
|
+
success: result.outcome === 'error' ? false : true,
|
|
685
|
+
outcome: result.outcome,
|
|
686
|
+
exitCode: result.exitCode,
|
|
687
|
+
statusCode: result.statusCode,
|
|
688
|
+
errorCode: result.errorCode,
|
|
689
|
+
output: result.text.length > 500 ? result.text.slice(0, 497) + '...' : result.text,
|
|
675
690
|
});
|
|
676
691
|
if (callId)
|
|
677
692
|
callMap.delete(callId);
|
|
@@ -698,6 +713,7 @@ export function parseCodexContent(content) {
|
|
|
698
713
|
agent: 'codex',
|
|
699
714
|
timestamp,
|
|
700
715
|
tool,
|
|
716
|
+
callId,
|
|
701
717
|
args,
|
|
702
718
|
path: patchPath,
|
|
703
719
|
});
|
|
@@ -713,14 +729,19 @@ export function parseCodexContent(content) {
|
|
|
713
729
|
else if (ptype === 'custom_tool_call_output') {
|
|
714
730
|
const callId = payload.call_id || payload.id;
|
|
715
731
|
const callInfo = callId ? callMap.get(callId) : undefined;
|
|
716
|
-
const
|
|
732
|
+
const result = structuredToolResult(payload.output);
|
|
717
733
|
events.push({
|
|
718
734
|
type: 'tool_result',
|
|
719
735
|
agent: 'codex',
|
|
720
736
|
timestamp,
|
|
721
737
|
tool: callInfo?.name,
|
|
722
|
-
|
|
723
|
-
|
|
738
|
+
callId,
|
|
739
|
+
success: result.outcome === 'error' ? false : true,
|
|
740
|
+
outcome: result.outcome,
|
|
741
|
+
exitCode: result.exitCode,
|
|
742
|
+
statusCode: result.statusCode,
|
|
743
|
+
errorCode: result.errorCode,
|
|
744
|
+
output: result.text.length > 500 ? result.text.slice(0, 497) + '...' : result.text,
|
|
724
745
|
});
|
|
725
746
|
if (callId)
|
|
726
747
|
callMap.delete(callId);
|
|
@@ -818,6 +839,7 @@ export function parseGemini(filePath) {
|
|
|
818
839
|
agent: 'gemini',
|
|
819
840
|
timestamp: tc.timestamp || timestamp,
|
|
820
841
|
tool: toolName,
|
|
842
|
+
callId: typeof tc.id === 'string' ? tc.id : undefined,
|
|
821
843
|
args,
|
|
822
844
|
command: ['run_shell_command', 'shell', 'bash'].includes(toolName) ? args.command : undefined,
|
|
823
845
|
path: args.file_path || args.path || undefined,
|
|
@@ -841,6 +863,7 @@ export function parseGemini(filePath) {
|
|
|
841
863
|
agent: 'gemini',
|
|
842
864
|
timestamp: tc.timestamp || timestamp,
|
|
843
865
|
tool: toolName,
|
|
866
|
+
callId: typeof tc.id === 'string' ? tc.id : undefined,
|
|
844
867
|
success: tc.status === 'success',
|
|
845
868
|
output: output.length > 500 ? output.slice(0, 497) + '...' : output,
|
|
846
869
|
});
|
|
@@ -1060,6 +1083,7 @@ export function parseAntigravity(dbPath) {
|
|
|
1060
1083
|
agent: 'antigravity',
|
|
1061
1084
|
timestamp,
|
|
1062
1085
|
tool: norm,
|
|
1086
|
+
callId: call.id,
|
|
1063
1087
|
args: a,
|
|
1064
1088
|
command: norm === 'Bash' ? a.CommandLine : undefined,
|
|
1065
1089
|
// Antigravity uses PascalCase arg keys; probe the known path-bearing ones.
|
|
@@ -1191,6 +1215,7 @@ export function parseGrok(filePath) {
|
|
|
1191
1215
|
agent: 'grok',
|
|
1192
1216
|
timestamp,
|
|
1193
1217
|
tool: toolName,
|
|
1218
|
+
callId: typeof call?.id === 'string' ? call.id : undefined,
|
|
1194
1219
|
args,
|
|
1195
1220
|
path: args.path || args.file_path || undefined,
|
|
1196
1221
|
command: typeof args.command === 'string' ? args.command : undefined,
|
|
@@ -1206,13 +1231,17 @@ export function parseGrok(filePath) {
|
|
|
1206
1231
|
const callId = typeof msg.tool_call_id === 'string' ? msg.tool_call_id : undefined;
|
|
1207
1232
|
const toolName = (callId && toolCallMap.get(callId)) || 'unknown';
|
|
1208
1233
|
const output = typeof msg.content === 'string' ? msg.content : extractText(msg.content);
|
|
1209
|
-
const
|
|
1234
|
+
const structuredError = msg.is_error === true;
|
|
1235
|
+
const structuredSuccess = msg.is_error === false;
|
|
1236
|
+
const displayAsError = structuredError || (typeof output === 'string' && output.startsWith('Error:'));
|
|
1210
1237
|
events.push({
|
|
1211
|
-
type:
|
|
1238
|
+
type: displayAsError ? 'error' : 'tool_result',
|
|
1212
1239
|
agent: 'grok',
|
|
1213
1240
|
timestamp,
|
|
1214
1241
|
tool: toolName,
|
|
1215
|
-
|
|
1242
|
+
callId,
|
|
1243
|
+
success: structuredError ? false : structuredSuccess ? true : undefined,
|
|
1244
|
+
outcome: structuredError ? 'error' : structuredSuccess ? 'ok' : 'unknown',
|
|
1216
1245
|
output: output.length > 500 ? output.slice(0, 497) + '...' : output,
|
|
1217
1246
|
});
|
|
1218
1247
|
if (callId)
|
|
@@ -1311,11 +1340,13 @@ export function parseOpenCode(filePath) {
|
|
|
1311
1340
|
const state = partData.state || {};
|
|
1312
1341
|
const input = state.input || {};
|
|
1313
1342
|
const output = state.output || '';
|
|
1343
|
+
const callId = typeof partData.callID === 'string' ? partData.callID : undefined;
|
|
1314
1344
|
events.push({
|
|
1315
1345
|
type: 'tool_use',
|
|
1316
1346
|
agent: 'opencode',
|
|
1317
1347
|
timestamp,
|
|
1318
1348
|
tool: toolName,
|
|
1349
|
+
callId,
|
|
1319
1350
|
args: input,
|
|
1320
1351
|
command: toolName === 'shell' ? input.command : undefined,
|
|
1321
1352
|
path: input.filePath || input.path || undefined,
|
|
@@ -1327,6 +1358,7 @@ export function parseOpenCode(filePath) {
|
|
|
1327
1358
|
agent: 'opencode',
|
|
1328
1359
|
timestamp,
|
|
1329
1360
|
tool: toolName,
|
|
1361
|
+
callId,
|
|
1330
1362
|
success: state.status === 'completed',
|
|
1331
1363
|
output: outputStr.length > 500 ? outputStr.slice(0, 497) + '...' : outputStr,
|
|
1332
1364
|
});
|
|
@@ -1370,8 +1402,10 @@ export function parseRush(filePath) {
|
|
|
1370
1402
|
continue;
|
|
1371
1403
|
}
|
|
1372
1404
|
const type = raw.type;
|
|
1373
|
-
const timestamp = raw.created_at
|
|
1374
|
-
const content = raw.content
|
|
1405
|
+
const timestamp = typeof raw.created_at === 'string' ? raw.created_at : new Date().toISOString();
|
|
1406
|
+
const content = raw.content && typeof raw.content === 'object' && !Array.isArray(raw.content)
|
|
1407
|
+
? raw.content
|
|
1408
|
+
: {};
|
|
1375
1409
|
if (type === 'message') {
|
|
1376
1410
|
const text = typeof content.text === 'string' ? content.text.trim() : '';
|
|
1377
1411
|
if (!text)
|
|
@@ -1394,9 +1428,11 @@ export function parseRush(filePath) {
|
|
|
1394
1428
|
});
|
|
1395
1429
|
}
|
|
1396
1430
|
else if (type === 'tool_call') {
|
|
1397
|
-
const toolName = raw.name
|
|
1398
|
-
const args = content.input
|
|
1399
|
-
|
|
1431
|
+
const toolName = typeof raw.name === 'string' && raw.name.length > 0 ? raw.name : 'unknown';
|
|
1432
|
+
const args = content.input && typeof content.input === 'object' && !Array.isArray(content.input)
|
|
1433
|
+
? content.input
|
|
1434
|
+
: {};
|
|
1435
|
+
const callId = typeof raw.tool_call_id === 'string' ? raw.tool_call_id : undefined;
|
|
1400
1436
|
if (callId)
|
|
1401
1437
|
toolCallMap.set(callId, { tool: toolName, args });
|
|
1402
1438
|
events.push({
|
|
@@ -1404,13 +1440,14 @@ export function parseRush(filePath) {
|
|
|
1404
1440
|
agent: 'rush',
|
|
1405
1441
|
timestamp,
|
|
1406
1442
|
tool: toolName,
|
|
1443
|
+
callId,
|
|
1407
1444
|
args,
|
|
1408
1445
|
path: args.file_path || args.path || undefined,
|
|
1409
1446
|
command: (toolName === 'Bash' || toolName === 'shell') ? args.command : undefined,
|
|
1410
1447
|
});
|
|
1411
1448
|
}
|
|
1412
1449
|
else if (type === 'tool_result') {
|
|
1413
|
-
const callId = raw.tool_call_id;
|
|
1450
|
+
const callId = typeof raw.tool_call_id === 'string' ? raw.tool_call_id : undefined;
|
|
1414
1451
|
const info = callId ? toolCallMap.get(callId) : undefined;
|
|
1415
1452
|
const output = content.output;
|
|
1416
1453
|
let outputStr = '';
|
|
@@ -1430,7 +1467,8 @@ export function parseRush(filePath) {
|
|
|
1430
1467
|
type: success ? 'tool_result' : 'error',
|
|
1431
1468
|
agent: 'rush',
|
|
1432
1469
|
timestamp,
|
|
1433
|
-
tool: info?.tool ?? raw.name,
|
|
1470
|
+
tool: info?.tool ?? (typeof raw.name === 'string' ? raw.name : 'unknown'),
|
|
1471
|
+
callId,
|
|
1434
1472
|
success,
|
|
1435
1473
|
output: outputStr.length > 500 ? outputStr.slice(0, 497) + '...' : outputStr,
|
|
1436
1474
|
});
|
|
@@ -1591,9 +1629,11 @@ export function parseKimi(filePath) {
|
|
|
1591
1629
|
}
|
|
1592
1630
|
else if (eventType === 'tool.call') {
|
|
1593
1631
|
const fn = event.function || {};
|
|
1594
|
-
const toolName = typeof event.name === 'string'
|
|
1632
|
+
const toolName = typeof event.name === 'string'
|
|
1633
|
+
? event.name
|
|
1634
|
+
: typeof fn.name === 'string' ? fn.name : 'unknown';
|
|
1595
1635
|
let args = {};
|
|
1596
|
-
if (event.args && typeof event.args === 'object') {
|
|
1636
|
+
if (event.args && typeof event.args === 'object' && !Array.isArray(event.args)) {
|
|
1597
1637
|
args = event.args;
|
|
1598
1638
|
}
|
|
1599
1639
|
else if (typeof fn.arguments === 'string') {
|
|
@@ -1604,10 +1644,11 @@ export function parseKimi(filePath) {
|
|
|
1604
1644
|
args = { _raw: fn.arguments };
|
|
1605
1645
|
}
|
|
1606
1646
|
}
|
|
1607
|
-
else if (fn.arguments && typeof fn.arguments === 'object') {
|
|
1647
|
+
else if (fn.arguments && typeof fn.arguments === 'object' && !Array.isArray(fn.arguments)) {
|
|
1608
1648
|
args = fn.arguments;
|
|
1609
1649
|
}
|
|
1610
|
-
const
|
|
1650
|
+
const rawCallId = event.toolCallId || event.uuid;
|
|
1651
|
+
const callId = typeof rawCallId === 'string' ? rawCallId : undefined;
|
|
1611
1652
|
if (callId) {
|
|
1612
1653
|
toolCallMap.set(callId, toolName);
|
|
1613
1654
|
}
|
|
@@ -1616,23 +1657,29 @@ export function parseKimi(filePath) {
|
|
|
1616
1657
|
agent: 'kimi',
|
|
1617
1658
|
timestamp,
|
|
1618
1659
|
tool: toolName,
|
|
1660
|
+
callId,
|
|
1619
1661
|
args,
|
|
1620
1662
|
path: args.path || args.file_path || undefined,
|
|
1621
1663
|
command: toolName === 'Bash' ? args.command : undefined,
|
|
1622
1664
|
});
|
|
1623
1665
|
}
|
|
1624
1666
|
else if (eventType === 'tool.result') {
|
|
1625
|
-
const
|
|
1667
|
+
const rawCallId = event.toolCallId || event.parentUuid;
|
|
1668
|
+
const callId = typeof rawCallId === 'string' ? rawCallId : undefined;
|
|
1626
1669
|
const toolName = (callId && toolCallMap.get(callId)) || 'unknown';
|
|
1627
1670
|
const result = event.result || {};
|
|
1628
1671
|
const output = typeof result.output === 'string' ? result.output : '';
|
|
1629
|
-
const
|
|
1672
|
+
const structuredError = result.isError === true;
|
|
1673
|
+
const structuredSuccess = result.isError === false;
|
|
1674
|
+
const displayAsError = structuredError || (output && output.startsWith('Error:'));
|
|
1630
1675
|
events.push({
|
|
1631
|
-
type:
|
|
1676
|
+
type: displayAsError ? 'error' : 'tool_result',
|
|
1632
1677
|
agent: 'kimi',
|
|
1633
1678
|
timestamp,
|
|
1634
1679
|
tool: toolName,
|
|
1635
|
-
|
|
1680
|
+
callId,
|
|
1681
|
+
success: structuredError ? false : structuredSuccess ? true : undefined,
|
|
1682
|
+
outcome: structuredError ? 'error' : structuredSuccess ? 'ok' : 'unknown',
|
|
1636
1683
|
output: output.length > 500 ? output.slice(0, 497) + '...' : output,
|
|
1637
1684
|
});
|
|
1638
1685
|
if (callId) {
|
|
@@ -1754,6 +1801,7 @@ function parseAnthropicMessageJsonl(filePath, agent) {
|
|
|
1754
1801
|
agent,
|
|
1755
1802
|
timestamp,
|
|
1756
1803
|
tool: toolName,
|
|
1804
|
+
callId: typeof block.id === 'string' ? block.id : undefined,
|
|
1757
1805
|
args: toolInput,
|
|
1758
1806
|
path: toolInput.file_path || toolInput.path || undefined,
|
|
1759
1807
|
command: (toolName === 'Bash' || toolName === 'Execute' || toolName === 'Shell') ? toolInput.command : undefined,
|
|
@@ -1769,11 +1817,14 @@ function parseAnthropicMessageJsonl(filePath, agent) {
|
|
|
1769
1817
|
? block.content.filter((c) => c.type === 'text').map((c) => c.text || '').join('\n')
|
|
1770
1818
|
: '';
|
|
1771
1819
|
if (isError) {
|
|
1772
|
-
events.push({
|
|
1820
|
+
events.push({
|
|
1821
|
+
type: 'error', agent, timestamp, tool: toolInfo?.tool,
|
|
1822
|
+
callId: toolId, outcome: 'error', content: output || 'Tool execution failed',
|
|
1823
|
+
});
|
|
1773
1824
|
}
|
|
1774
1825
|
else {
|
|
1775
1826
|
events.push({
|
|
1776
|
-
type: 'tool_result', agent, timestamp, tool: toolInfo?.tool, success: true,
|
|
1827
|
+
type: 'tool_result', agent, timestamp, tool: toolInfo?.tool, callId: toolId, success: true,
|
|
1777
1828
|
output: output.length > 500 ? output.slice(0, 497) + '...' : output,
|
|
1778
1829
|
});
|
|
1779
1830
|
}
|
|
@@ -1,4 +1,33 @@
|
|
|
1
|
+
import { type DeviceProfile } from '../devices/registry.js';
|
|
2
|
+
import { type RemoteAgentsJsonParseResult } from '../remote-agents-json.js';
|
|
1
3
|
import type { SessionMeta } from './types.js';
|
|
4
|
+
import { type ToolProgramCountEnvelope, type ToolSearchEnvelope } from './tool-index.js';
|
|
5
|
+
export declare const REMOTE_STDOUT_MAX_BYTES: number;
|
|
6
|
+
export declare const REMOTE_TOOL_AGGREGATE_MAX_BYTES: number;
|
|
7
|
+
export interface RemoteToolByteBudget {
|
|
8
|
+
remainingBytes: number;
|
|
9
|
+
exhausted: boolean;
|
|
10
|
+
}
|
|
11
|
+
/** Preserve UTF-8 code points when SSH splits them across stdout chunks. */
|
|
12
|
+
export declare class RemoteUtf8Accumulator {
|
|
13
|
+
private readonly decoder;
|
|
14
|
+
private value;
|
|
15
|
+
write(chunk: Buffer): void;
|
|
16
|
+
end(): string;
|
|
17
|
+
current(): string;
|
|
18
|
+
}
|
|
19
|
+
/** Claim received bytes against one fleet-query budget before retaining them. */
|
|
20
|
+
export declare function consumeRemoteToolByteBudget(budget: RemoteToolByteBudget, bytes: number): boolean;
|
|
21
|
+
/** Charge sanitized, machine-stamped evidence because redaction may expand it. */
|
|
22
|
+
export declare function consumeParsedRemoteToolSearchBudget(budget: RemoteToolByteBudget, envelope: ToolSearchEnvelope): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* The command run on each peer: answer for itself, as JSON, without recursing.
|
|
25
|
+
* `forwardedArgs` carry the caller's own query/filters (already including the
|
|
26
|
+
* leading `sessions` and a `--json`) so each peer returns a comparable slice.
|
|
27
|
+
* A Windows peer gets a PowerShell invocation (ssh lands in cmd.exe/PowerShell
|
|
28
|
+
* there, where `bash -lc` is not a command); every other OS keeps `bash -lc`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function remoteListCommand(forwardedArgs: string[], os?: string): string;
|
|
2
31
|
/**
|
|
3
32
|
* Parse a peer's `sessions --json` stdout into `SessionMeta[]`, tagging each
|
|
4
33
|
* with `machine`. Defensive against version skew / partial output: non-JSON or
|
|
@@ -12,6 +41,17 @@ export declare function parseRemoteListPayload(stdout: string, machine: string,
|
|
|
12
41
|
items: SessionMeta[];
|
|
13
42
|
valid: boolean;
|
|
14
43
|
};
|
|
44
|
+
/** Run one remote `agents sessions … --json` and capture stdout. Resolves
|
|
45
|
+
* `{ code: null }` on spawn error or timeout (host treated as dead). */
|
|
46
|
+
export declare function sshCapture(target: string, remoteCmd: string, timeoutMs: number, aggregateBudget?: RemoteToolByteBudget, options?: {
|
|
47
|
+
multiplex?: boolean;
|
|
48
|
+
port?: number;
|
|
49
|
+
hostKeyOpts?: string[];
|
|
50
|
+
}): Promise<{
|
|
51
|
+
code: number | null;
|
|
52
|
+
stdout: string;
|
|
53
|
+
aggregateBudgetExceeded?: boolean;
|
|
54
|
+
}>;
|
|
15
55
|
export interface RemoteListResult {
|
|
16
56
|
sessions: SessionMeta[];
|
|
17
57
|
/** How many peer machines we attempted to reach (drives the empty-fleet tip). */
|
|
@@ -24,6 +64,8 @@ export interface RemoteListResult {
|
|
|
24
64
|
*/
|
|
25
65
|
unreachable: string[];
|
|
26
66
|
}
|
|
67
|
+
/** Keep browse and tool-search fan-out on the same automatic peer set. */
|
|
68
|
+
export declare function isAutomaticSessionPeer(d: DeviceProfile, self: string): boolean;
|
|
27
69
|
/**
|
|
28
70
|
* Gather listing sessions from other machines. With an explicit `hosts` list
|
|
29
71
|
* (from `--host`), fan out to exactly those. Otherwise sweep the registered,
|
|
@@ -32,6 +74,35 @@ export interface RemoteListResult {
|
|
|
32
74
|
* already `--json`) so every peer returns the same slice this machine asked for.
|
|
33
75
|
*/
|
|
34
76
|
export declare function gatherRemoteList(forwardedArgs: string[], hosts?: string[]): Promise<RemoteListResult>;
|
|
77
|
+
export interface RemoteToolSearchResult {
|
|
78
|
+
envelopes: Array<{
|
|
79
|
+
machine: string;
|
|
80
|
+
envelope: ToolSearchEnvelope;
|
|
81
|
+
}>;
|
|
82
|
+
deviceCount: number;
|
|
83
|
+
unreachable: string[];
|
|
84
|
+
truncated: string[];
|
|
85
|
+
}
|
|
86
|
+
export interface RemoteToolProgramCountResult {
|
|
87
|
+
envelopes: Array<{
|
|
88
|
+
machine: string;
|
|
89
|
+
envelope: ToolProgramCountEnvelope;
|
|
90
|
+
}>;
|
|
91
|
+
deviceCount: number;
|
|
92
|
+
unreachable: string[];
|
|
93
|
+
}
|
|
94
|
+
export declare function parseRemoteToolProgramCount(stdout: string, machine: string, expectedProgram: string): RemoteAgentsJsonParseResult<{
|
|
95
|
+
machine: string;
|
|
96
|
+
envelope: ToolProgramCountEnvelope;
|
|
97
|
+
}>;
|
|
98
|
+
export declare function gatherRemoteToolProgramCounts(forwardedArgs: string[], hosts: string[] | undefined, expectedProgram: string): Promise<RemoteToolProgramCountResult>;
|
|
99
|
+
export declare function parseRemoteToolSearch(stdout: string, machine: string, expectedClauses?: string[]): ToolSearchEnvelope | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* Fleet sibling of {@link gatherRemoteList} for the versioned tool-search
|
|
102
|
+
* envelope. Each peer executes the same local-only query against its own
|
|
103
|
+
* SQLite index; only compact matches cross SSH.
|
|
104
|
+
*/
|
|
105
|
+
export declare function gatherRemoteToolSearch(forwardedArgs: string[], hosts?: string[], maxAggregateBytes?: number, expectedClauses?: string[]): Promise<RemoteToolSearchResult>;
|
|
35
106
|
/** Resolve a peer's SSH target (and OS) from the device registry by its
|
|
36
107
|
* normalized machine id — the same id the fan-out tags rows with. Returns
|
|
37
108
|
* undefined when no registered device with an address matches. */
|