@formigio/fazemos-cli 0.2.1 → 0.2.3
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/index.js +296 -10
- package/dist/index.js.map +1 -1
- package/dist/monitor.d.ts +2 -0
- package/dist/monitor.js +533 -0
- package/dist/monitor.js.map +1 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -5,9 +5,9 @@ import { config, getEnv, getToken, getActiveOrgId, setActiveOrgId, addEnvironmen
|
|
|
5
5
|
import { login, signup, confirmSignup, adminLogin } from './auth.js';
|
|
6
6
|
import { api } from './api.js';
|
|
7
7
|
import { execSync } from 'child_process';
|
|
8
|
-
import { readFileSync } from 'fs';
|
|
8
|
+
import { readFileSync, readdirSync } from 'fs';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
|
-
import { dirname, resolve } from 'path';
|
|
10
|
+
import { dirname, resolve, basename } from 'path';
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf-8'));
|
|
13
13
|
function parseNumber(val) {
|
|
@@ -1358,7 +1358,8 @@ executions
|
|
|
1358
1358
|
.command('show')
|
|
1359
1359
|
.description('Show execution detail')
|
|
1360
1360
|
.argument('<id>', 'Execution ID')
|
|
1361
|
-
.
|
|
1361
|
+
.option('-c, --context', 'Show full execution context (prompt, model, repos, worksheet)')
|
|
1362
|
+
.action(async (id, opts) => {
|
|
1362
1363
|
try {
|
|
1363
1364
|
const data = await api('GET', `/api/executions/${id}`);
|
|
1364
1365
|
const e = data.execution;
|
|
@@ -1382,6 +1383,30 @@ executions
|
|
|
1382
1383
|
console.log(` Started: ${e.started_at}`);
|
|
1383
1384
|
if (e.completed_at)
|
|
1384
1385
|
console.log(` Completed: ${e.completed_at}`);
|
|
1386
|
+
if (opts.context && e.context) {
|
|
1387
|
+
const ctx = e.context;
|
|
1388
|
+
console.log(chalk.cyan(`\n Context:`));
|
|
1389
|
+
if (ctx.model)
|
|
1390
|
+
console.log(` Model: ${ctx.model}`);
|
|
1391
|
+
if (ctx.maxBudgetUsd)
|
|
1392
|
+
console.log(` Budget: $${ctx.maxBudgetUsd}`);
|
|
1393
|
+
if (ctx.repos?.length)
|
|
1394
|
+
console.log(` Repos: ${ctx.repos.map((r) => r.name || r).join(', ')}`);
|
|
1395
|
+
if (ctx.worksheetName)
|
|
1396
|
+
console.log(` Worksheet: ${ctx.worksheetName}`);
|
|
1397
|
+
if (ctx.worksheetPurpose)
|
|
1398
|
+
console.log(` Purpose: ${ctx.worksheetPurpose}`);
|
|
1399
|
+
if (ctx.actionDescription)
|
|
1400
|
+
console.log(` Action: ${ctx.actionDescription}`);
|
|
1401
|
+
if (ctx.outcomes?.length) {
|
|
1402
|
+
console.log(chalk.cyan(` Outcomes:`));
|
|
1403
|
+
for (const o of ctx.outcomes) {
|
|
1404
|
+
console.log(` ${o.status === 'achieved' ? '✓' : '○'} ${o.description || o.name}`);
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
if (ctx.prompt)
|
|
1408
|
+
console.log(` Prompt: ${ctx.prompt}`);
|
|
1409
|
+
}
|
|
1385
1410
|
}
|
|
1386
1411
|
catch (err) {
|
|
1387
1412
|
console.error(chalk.red(err.message));
|
|
@@ -1457,6 +1482,141 @@ executions
|
|
|
1457
1482
|
process.exit(1);
|
|
1458
1483
|
}
|
|
1459
1484
|
});
|
|
1485
|
+
executions
|
|
1486
|
+
.command('logs')
|
|
1487
|
+
.description('Show execution output (polls if running)')
|
|
1488
|
+
.argument('<id>', 'Execution ID')
|
|
1489
|
+
.option('-f, --follow', 'Keep polling until execution completes')
|
|
1490
|
+
.action(async (id, opts) => {
|
|
1491
|
+
try {
|
|
1492
|
+
const poll = async () => {
|
|
1493
|
+
const data = await api('GET', `/api/executions/${id}`);
|
|
1494
|
+
return data.execution;
|
|
1495
|
+
};
|
|
1496
|
+
let e = await poll();
|
|
1497
|
+
const isTerminal = (status) => ['completed', 'failed', 'cancelled'].includes(status);
|
|
1498
|
+
const formatOutput = (ex) => {
|
|
1499
|
+
if (ex.output_data) {
|
|
1500
|
+
return typeof ex.output_data === 'string' ? ex.output_data : JSON.stringify(ex.output_data, null, 2);
|
|
1501
|
+
}
|
|
1502
|
+
if (ex.output_text)
|
|
1503
|
+
return ex.output_text;
|
|
1504
|
+
return '';
|
|
1505
|
+
};
|
|
1506
|
+
// Print current output
|
|
1507
|
+
const initialOutput = formatOutput(e);
|
|
1508
|
+
if (initialOutput)
|
|
1509
|
+
console.log(initialOutput);
|
|
1510
|
+
if (isTerminal(e.status)) {
|
|
1511
|
+
if (!initialOutput)
|
|
1512
|
+
console.log(chalk.yellow('No output'));
|
|
1513
|
+
console.log(chalk.gray(`\n[${e.status}]`));
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1516
|
+
if (!opts.follow) {
|
|
1517
|
+
console.log(chalk.yellow(`\n[${e.status} — use --follow to poll]`));
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
// Poll until complete
|
|
1521
|
+
let lastLen = initialOutput.length;
|
|
1522
|
+
while (!isTerminal(e.status)) {
|
|
1523
|
+
await new Promise(r => setTimeout(r, 3000));
|
|
1524
|
+
e = await poll();
|
|
1525
|
+
const currentOutput = formatOutput(e);
|
|
1526
|
+
if (currentOutput.length > lastLen) {
|
|
1527
|
+
process.stdout.write(currentOutput.slice(lastLen));
|
|
1528
|
+
lastLen = currentOutput.length;
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
console.log(chalk.gray(`\n[${e.status}]`));
|
|
1532
|
+
}
|
|
1533
|
+
catch (err) {
|
|
1534
|
+
console.error(chalk.red(err.message));
|
|
1535
|
+
process.exit(1);
|
|
1536
|
+
}
|
|
1537
|
+
});
|
|
1538
|
+
executions
|
|
1539
|
+
.command('cloudwatch-logs')
|
|
1540
|
+
.alias('cw')
|
|
1541
|
+
.description('Show container logs from CloudWatch')
|
|
1542
|
+
.argument('<id>', 'Execution ID')
|
|
1543
|
+
.option('-l, --limit <n>', 'Max log lines', parseNumber, 100)
|
|
1544
|
+
.option('-f, --follow', 'Poll for new lines until execution completes')
|
|
1545
|
+
.option('--since <duration>', 'Show logs since (e.g., 5m, 1h)')
|
|
1546
|
+
.action(async (id, opts) => {
|
|
1547
|
+
try {
|
|
1548
|
+
const isTerminal = (status) => ['completed', 'failed', 'cancelled'].includes(status);
|
|
1549
|
+
const parseSince = (since) => {
|
|
1550
|
+
const match = since.match(/^(\d+)(m|h|d)$/);
|
|
1551
|
+
if (!match)
|
|
1552
|
+
throw new Error('Invalid --since format. Use e.g. 5m, 1h, 2d');
|
|
1553
|
+
const val = parseInt(match[1], 10);
|
|
1554
|
+
const unit = match[2];
|
|
1555
|
+
const multipliers = { m: 60000, h: 3600000, d: 86400000 };
|
|
1556
|
+
return Date.now() - val * multipliers[unit];
|
|
1557
|
+
};
|
|
1558
|
+
const startTime = opts.since ? String(parseSince(opts.since)) : undefined;
|
|
1559
|
+
const fetchLogs = async (nextToken) => {
|
|
1560
|
+
const params = new URLSearchParams();
|
|
1561
|
+
params.set('limit', String(opts.limit));
|
|
1562
|
+
if (startTime)
|
|
1563
|
+
params.set('startTime', startTime);
|
|
1564
|
+
if (nextToken)
|
|
1565
|
+
params.set('nextToken', nextToken);
|
|
1566
|
+
return await api('GET', `/api/executions/${id}/cloudwatch-logs?${params}`);
|
|
1567
|
+
};
|
|
1568
|
+
const formatLine = (event) => {
|
|
1569
|
+
const ts = new Date(event.timestamp);
|
|
1570
|
+
const hh = String(ts.getHours()).padStart(2, '0');
|
|
1571
|
+
const mm = String(ts.getMinutes()).padStart(2, '0');
|
|
1572
|
+
const ss = String(ts.getSeconds()).padStart(2, '0');
|
|
1573
|
+
return `${chalk.gray(`[${hh}:${mm}:${ss}]`)} ${event.message}`;
|
|
1574
|
+
};
|
|
1575
|
+
// Initial fetch
|
|
1576
|
+
let data = await fetchLogs();
|
|
1577
|
+
if (!data.logs?.length && !opts.follow) {
|
|
1578
|
+
console.log(chalk.yellow(data.message || 'No log events'));
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
for (const event of data.logs || []) {
|
|
1582
|
+
console.log(formatLine(event));
|
|
1583
|
+
}
|
|
1584
|
+
if (!opts.follow)
|
|
1585
|
+
return;
|
|
1586
|
+
// Poll loop
|
|
1587
|
+
let token = data.nextToken;
|
|
1588
|
+
while (true) {
|
|
1589
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
1590
|
+
// Check execution status
|
|
1591
|
+
const exData = await api('GET', `/api/executions/${id}`);
|
|
1592
|
+
const status = exData.execution?.status;
|
|
1593
|
+
// Fetch new logs
|
|
1594
|
+
data = await fetchLogs(token);
|
|
1595
|
+
for (const event of data.logs || []) {
|
|
1596
|
+
console.log(formatLine(event));
|
|
1597
|
+
}
|
|
1598
|
+
token = data.nextToken;
|
|
1599
|
+
if (isTerminal(status)) {
|
|
1600
|
+
// Drain remaining log pages
|
|
1601
|
+
let prevToken;
|
|
1602
|
+
while (token && token !== prevToken) {
|
|
1603
|
+
prevToken = token;
|
|
1604
|
+
data = await fetchLogs(token);
|
|
1605
|
+
for (const event of data.logs || []) {
|
|
1606
|
+
console.log(formatLine(event));
|
|
1607
|
+
}
|
|
1608
|
+
token = data.nextToken;
|
|
1609
|
+
}
|
|
1610
|
+
console.log(chalk.gray(`\n[${status}]`));
|
|
1611
|
+
break;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
catch (err) {
|
|
1616
|
+
console.error(chalk.red(err.message));
|
|
1617
|
+
process.exit(1);
|
|
1618
|
+
}
|
|
1619
|
+
});
|
|
1460
1620
|
// ── My Work ─────────────────────────────────────────────────
|
|
1461
1621
|
program
|
|
1462
1622
|
.command('my-work')
|
|
@@ -1536,6 +1696,27 @@ program
|
|
|
1536
1696
|
});
|
|
1537
1697
|
// ── Agents ──────────────────────────────────────────────────
|
|
1538
1698
|
const agentsCmd = program.command('agents').description('Agent management');
|
|
1699
|
+
/** Resolve agent name or UUID to member ID */
|
|
1700
|
+
async function resolveAgentId(nameOrId) {
|
|
1701
|
+
if (/^[0-9a-f]{8}-[0-9a-f]{4}-/.test(nameOrId))
|
|
1702
|
+
return nameOrId;
|
|
1703
|
+
const orgId = getActiveOrgId();
|
|
1704
|
+
if (!orgId) {
|
|
1705
|
+
console.error(chalk.red('No active org'));
|
|
1706
|
+
process.exit(1);
|
|
1707
|
+
}
|
|
1708
|
+
const membersData = await api('GET', `/api/organizations/${orgId}/members?type=agent`);
|
|
1709
|
+
const norm = (s) => s.toLowerCase().replace(/[-_\s]+/g, ' ').trim();
|
|
1710
|
+
const agent = membersData.members.find((m) => norm(m.display_name) === norm(nameOrId));
|
|
1711
|
+
if (!agent) {
|
|
1712
|
+
console.error(chalk.red(`Agent "${nameOrId}" not found. Available:`));
|
|
1713
|
+
for (const m of membersData.members.filter((m) => m.member_type === 'agent')) {
|
|
1714
|
+
console.log(` ${m.display_name} — ${m.id}`);
|
|
1715
|
+
}
|
|
1716
|
+
process.exit(1);
|
|
1717
|
+
}
|
|
1718
|
+
return agent.id;
|
|
1719
|
+
}
|
|
1539
1720
|
agentsCmd
|
|
1540
1721
|
.command('register')
|
|
1541
1722
|
.description('Register an agent')
|
|
@@ -1594,9 +1775,10 @@ agentsCmd
|
|
|
1594
1775
|
agentsCmd
|
|
1595
1776
|
.command('show')
|
|
1596
1777
|
.description('Show agent status and details')
|
|
1597
|
-
.argument('<id>', 'Agent member ID')
|
|
1778
|
+
.argument('<id>', 'Agent name or member ID')
|
|
1598
1779
|
.action(async (id) => {
|
|
1599
1780
|
try {
|
|
1781
|
+
id = await resolveAgentId(id);
|
|
1600
1782
|
const data = await api('GET', `/api/agents/${id}/status`);
|
|
1601
1783
|
console.log(chalk.cyan(`Agent: ${data.display_name}`));
|
|
1602
1784
|
console.log(` ID: ${data.id}`);
|
|
@@ -1625,10 +1807,11 @@ agentsCmd
|
|
|
1625
1807
|
agentsCmd
|
|
1626
1808
|
.command('metrics')
|
|
1627
1809
|
.description('Show agent execution metrics')
|
|
1628
|
-
.argument('<id>', 'Agent member ID')
|
|
1810
|
+
.argument('<id>', 'Agent name or member ID')
|
|
1629
1811
|
.option('-w, --window <hours>', 'Time window in hours', '24')
|
|
1630
1812
|
.action(async (id, opts) => {
|
|
1631
1813
|
try {
|
|
1814
|
+
id = await resolveAgentId(id);
|
|
1632
1815
|
const data = await api('GET', `/api/agents/${id}/metrics?window_hours=${opts.window}`);
|
|
1633
1816
|
const e = data.executions;
|
|
1634
1817
|
console.log(chalk.cyan(`Metrics (last ${data.window_hours}h):`));
|
|
@@ -1655,12 +1838,13 @@ agentsCmd
|
|
|
1655
1838
|
agentsCmd
|
|
1656
1839
|
.command('events')
|
|
1657
1840
|
.description('Show agent event log')
|
|
1658
|
-
.argument('<id>', 'Agent member ID')
|
|
1841
|
+
.argument('<id>', 'Agent name or member ID')
|
|
1659
1842
|
.option('-t, --type <type>', 'Filter by event type')
|
|
1660
1843
|
.option('-e, --execution <id>', 'Filter by execution ID')
|
|
1661
1844
|
.option('-l, --limit <n>', 'Max events to show', '20')
|
|
1662
1845
|
.action(async (id, opts) => {
|
|
1663
1846
|
try {
|
|
1847
|
+
id = await resolveAgentId(id);
|
|
1664
1848
|
const params = [`limit=${opts.limit}`];
|
|
1665
1849
|
if (opts.type)
|
|
1666
1850
|
params.push(`event_type=${opts.type}`);
|
|
@@ -1689,9 +1873,10 @@ agentsCmd
|
|
|
1689
1873
|
agentsCmd
|
|
1690
1874
|
.command('budget')
|
|
1691
1875
|
.description('Check agent budget status')
|
|
1692
|
-
.argument('<id>', 'Agent member ID')
|
|
1876
|
+
.argument('<id>', 'Agent name or member ID')
|
|
1693
1877
|
.action(async (id) => {
|
|
1694
1878
|
try {
|
|
1879
|
+
id = await resolveAgentId(id);
|
|
1695
1880
|
const data = await api('GET', `/api/agents/${id}/budget`);
|
|
1696
1881
|
const icon = data.allowed ? chalk.green('✓') : chalk.red('✗');
|
|
1697
1882
|
console.log(` ${icon} Budget: ${data.allowed ? 'OK' : 'EXCEEDED'}`);
|
|
@@ -1713,12 +1898,13 @@ agentsCmd
|
|
|
1713
1898
|
agentsCmd
|
|
1714
1899
|
.command('heartbeat')
|
|
1715
1900
|
.description('Send agent heartbeat')
|
|
1716
|
-
.argument('<id>', 'Agent member ID')
|
|
1901
|
+
.argument('<id>', 'Agent name or member ID')
|
|
1717
1902
|
.option('-s, --status <status>', 'Agent status (idle, busy, error)', 'idle')
|
|
1718
1903
|
.option('-e, --execution <id>', 'Current execution ID')
|
|
1719
1904
|
.option('-d, --details <json>', 'Additional details as JSON')
|
|
1720
1905
|
.action(async (id, opts) => {
|
|
1721
1906
|
try {
|
|
1907
|
+
id = await resolveAgentId(id);
|
|
1722
1908
|
const body = { status: opts.status };
|
|
1723
1909
|
if (opts.execution)
|
|
1724
1910
|
body.currentExecutionId = opts.execution;
|
|
@@ -1735,12 +1921,13 @@ agentsCmd
|
|
|
1735
1921
|
agentsCmd
|
|
1736
1922
|
.command('event')
|
|
1737
1923
|
.description('Log an agent event')
|
|
1738
|
-
.argument('<id>', 'Agent member ID')
|
|
1924
|
+
.argument('<id>', 'Agent name or member ID')
|
|
1739
1925
|
.requiredOption('-t, --type <type>', 'Event type (status_change, error, budget_warning, etc.)')
|
|
1740
1926
|
.option('-e, --execution <id>', 'Related execution ID')
|
|
1741
1927
|
.option('-d, --details <json>', 'Event details as JSON')
|
|
1742
1928
|
.action(async (id, opts) => {
|
|
1743
1929
|
try {
|
|
1930
|
+
id = await resolveAgentId(id);
|
|
1744
1931
|
const body = { eventType: opts.type };
|
|
1745
1932
|
if (opts.execution)
|
|
1746
1933
|
body.executionId = opts.execution;
|
|
@@ -1757,9 +1944,10 @@ agentsCmd
|
|
|
1757
1944
|
agentsCmd
|
|
1758
1945
|
.command('work')
|
|
1759
1946
|
.description('Show consolidated work assignments for an agent')
|
|
1760
|
-
.argument('<id>', 'Agent member ID')
|
|
1947
|
+
.argument('<id>', 'Agent name or member ID')
|
|
1761
1948
|
.action(async (id) => {
|
|
1762
1949
|
try {
|
|
1950
|
+
id = await resolveAgentId(id);
|
|
1763
1951
|
const data = await api('GET', `/api/agents/${id}/work`);
|
|
1764
1952
|
console.log(chalk.cyan(`Agent Status: ${data.agent_status || 'unknown'}`));
|
|
1765
1953
|
// Budget summary
|
|
@@ -1798,6 +1986,84 @@ agentsCmd
|
|
|
1798
1986
|
process.exit(1);
|
|
1799
1987
|
}
|
|
1800
1988
|
});
|
|
1989
|
+
agentsCmd
|
|
1990
|
+
.command('upload-definition')
|
|
1991
|
+
.description('Upload an agent definition file to Fazemos')
|
|
1992
|
+
.argument('<name>', 'Agent name')
|
|
1993
|
+
.argument('<file>', 'Path to agent definition .md file')
|
|
1994
|
+
.action(async (name, file) => {
|
|
1995
|
+
try {
|
|
1996
|
+
// Resolve agent name to member ID
|
|
1997
|
+
const orgId = getActiveOrgId();
|
|
1998
|
+
if (!orgId) {
|
|
1999
|
+
console.error(chalk.red('No active org'));
|
|
2000
|
+
process.exit(1);
|
|
2001
|
+
}
|
|
2002
|
+
const membersData = await api('GET', `/api/organizations/${orgId}/members?type=agent`);
|
|
2003
|
+
const norm = (s) => s.toLowerCase().replace(/[-_\s]+/g, ' ').trim();
|
|
2004
|
+
const agent = membersData.members.find((m) => norm(m.display_name) === norm(name));
|
|
2005
|
+
if (!agent) {
|
|
2006
|
+
console.error(chalk.red(`Agent "${name}" not found`));
|
|
2007
|
+
process.exit(1);
|
|
2008
|
+
}
|
|
2009
|
+
// Read file and strip YAML frontmatter
|
|
2010
|
+
const raw = readFileSync(resolve(file), 'utf-8');
|
|
2011
|
+
const body = raw.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '').trim();
|
|
2012
|
+
await api('PATCH', `/api/members/${agent.id}/agent-config`, { systemPrompt: body });
|
|
2013
|
+
console.log(chalk.green(`Uploaded definition for ${agent.display_name} (${body.length} chars)`));
|
|
2014
|
+
}
|
|
2015
|
+
catch (err) {
|
|
2016
|
+
console.error(chalk.red(err.message));
|
|
2017
|
+
process.exit(1);
|
|
2018
|
+
}
|
|
2019
|
+
});
|
|
2020
|
+
agentsCmd
|
|
2021
|
+
.command('upload-all')
|
|
2022
|
+
.description('Upload all agent definitions from a directory')
|
|
2023
|
+
.argument('<dir>', 'Directory containing .md agent definition files')
|
|
2024
|
+
.action(async (dir) => {
|
|
2025
|
+
try {
|
|
2026
|
+
const orgId = getActiveOrgId();
|
|
2027
|
+
if (!orgId) {
|
|
2028
|
+
console.error(chalk.red('No active org'));
|
|
2029
|
+
process.exit(1);
|
|
2030
|
+
}
|
|
2031
|
+
const membersData = await api('GET', `/api/organizations/${orgId}/members?type=agent`);
|
|
2032
|
+
const agents = membersData.members.filter((m) => m.member_type === 'agent');
|
|
2033
|
+
const resolvedDir = resolve(dir);
|
|
2034
|
+
const files = readdirSync(resolvedDir).filter(f => f.endsWith('.md'));
|
|
2035
|
+
if (!files.length) {
|
|
2036
|
+
console.log(chalk.yellow(`No .md files found in ${resolvedDir}`));
|
|
2037
|
+
return;
|
|
2038
|
+
}
|
|
2039
|
+
let uploaded = 0;
|
|
2040
|
+
let skipped = 0;
|
|
2041
|
+
const norm = (s) => s.toLowerCase().replace(/[-_\s]+/g, ' ').trim();
|
|
2042
|
+
for (const file of files) {
|
|
2043
|
+
const raw = readFileSync(resolve(resolvedDir, file), 'utf-8');
|
|
2044
|
+
// Extract name from frontmatter (name: field), fall back to filename
|
|
2045
|
+
const frontmatterMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
2046
|
+
const frontmatter = frontmatterMatch ? frontmatterMatch[1] : '';
|
|
2047
|
+
const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
|
|
2048
|
+
const name = nameMatch ? nameMatch[1].trim() : basename(file, '.md');
|
|
2049
|
+
const agent = agents.find((a) => norm(a.display_name) === norm(name));
|
|
2050
|
+
if (!agent) {
|
|
2051
|
+
console.log(chalk.yellow(` ⊘ ${name} — no matching agent`));
|
|
2052
|
+
skipped++;
|
|
2053
|
+
continue;
|
|
2054
|
+
}
|
|
2055
|
+
const body = raw.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '').trim();
|
|
2056
|
+
await api('PATCH', `/api/members/${agent.id}/agent-config`, { systemPrompt: body });
|
|
2057
|
+
console.log(chalk.green(` ✓ ${agent.display_name} (${body.length} chars)`));
|
|
2058
|
+
uploaded++;
|
|
2059
|
+
}
|
|
2060
|
+
console.log(`\n${uploaded} uploaded, ${skipped} skipped`);
|
|
2061
|
+
}
|
|
2062
|
+
catch (err) {
|
|
2063
|
+
console.error(chalk.red(err.message));
|
|
2064
|
+
process.exit(1);
|
|
2065
|
+
}
|
|
2066
|
+
});
|
|
1801
2067
|
// ── Health ──────────────────────────────────────────────────
|
|
1802
2068
|
program
|
|
1803
2069
|
.command('health')
|
|
@@ -1879,5 +2145,25 @@ apiKeys
|
|
|
1879
2145
|
process.exit(1);
|
|
1880
2146
|
}
|
|
1881
2147
|
});
|
|
2148
|
+
// ── Monitor ─────────────────────────────────────────────────
|
|
2149
|
+
program
|
|
2150
|
+
.command('monitor')
|
|
2151
|
+
.description('Launch web-based execution monitor (live logs, status)')
|
|
2152
|
+
.option('-p, --port <port>', 'Port to listen on', '4600')
|
|
2153
|
+
.action(async (opts) => {
|
|
2154
|
+
try {
|
|
2155
|
+
const port = parseInt(opts.port, 10);
|
|
2156
|
+
const { startMonitor } = await import('./monitor.js');
|
|
2157
|
+
await startMonitor(port);
|
|
2158
|
+
console.log(chalk.green(`\n ◆ Fazemos Execution Monitor`));
|
|
2159
|
+
console.log(` ${chalk.cyan(`http://localhost:${port}`)}`);
|
|
2160
|
+
console.log(chalk.gray(`\n Proxying API calls with your current auth session`));
|
|
2161
|
+
console.log(chalk.gray(` Press Ctrl+C to stop\n`));
|
|
2162
|
+
}
|
|
2163
|
+
catch (err) {
|
|
2164
|
+
console.error(chalk.red(err.message));
|
|
2165
|
+
process.exit(1);
|
|
2166
|
+
}
|
|
2167
|
+
});
|
|
1882
2168
|
program.parse();
|
|
1883
2169
|
//# sourceMappingURL=index.js.map
|