projax 3.3.70 → 3.3.71
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-runner.d.ts +60 -0
- package/dist/agent-runner.js +382 -0
- package/dist/api/database.d.ts +38 -1
- package/dist/api/database.d.ts.map +1 -1
- package/dist/api/database.js +327 -0
- package/dist/api/database.js.map +1 -1
- package/dist/api/routes/agents.d.ts +4 -0
- package/dist/api/routes/agents.d.ts.map +1 -0
- package/dist/api/routes/agents.js +375 -0
- package/dist/api/routes/agents.js.map +1 -0
- package/dist/api/routes/index.d.ts.map +1 -1
- package/dist/api/routes/index.js +4 -0
- package/dist/api/routes/index.js.map +1 -1
- package/dist/api/routes/todos.d.ts +4 -0
- package/dist/api/routes/todos.d.ts.map +1 -0
- package/dist/api/routes/todos.js +595 -0
- package/dist/api/routes/todos.js.map +1 -0
- package/dist/api/types.d.ts +67 -0
- package/dist/api/types.d.ts.map +1 -1
- package/dist/core/database.d.ts +47 -0
- package/dist/core/database.js +48 -0
- package/dist/core-bridge.d.ts +1 -1
- package/dist/electron/core/database.d.ts +47 -0
- package/dist/electron/core/database.js +48 -0
- package/dist/electron/renderer/assets/index-6afBeDFD.js +66 -0
- package/dist/electron/renderer/assets/index-Bd3aFi7B.css +1 -0
- package/dist/electron/renderer/index.html +2 -2
- package/dist/index.js +6 -175
- package/dist/octopus-cli.d.ts +2 -0
- package/dist/octopus-cli.js +45 -0
- package/dist/octopus-show-tui.d.ts +1 -0
- package/dist/octopus-show-tui.js +802 -0
- package/dist/octopus-tui.d.ts +1 -0
- package/dist/octopus-tui.js +115 -0
- package/dist/prxi.js +373 -63
- package/dist/prxi.tsx +472 -65
- package/package.json +7 -2
- package/dist/electron/renderer/assets/index-Cd1mTO3s.js +0 -66
- package/dist/electron/renderer/assets/index-DJDPi0kp.css +0 -1
package/dist/prxi.js
CHANGED
|
@@ -49,6 +49,7 @@ process.stderr.on('error', (err) => {
|
|
|
49
49
|
});
|
|
50
50
|
const core_bridge_1 = require("./core-bridge");
|
|
51
51
|
const script_runner_1 = require("./script-runner");
|
|
52
|
+
const agent_runner_1 = require("./agent-runner");
|
|
52
53
|
const child_process_1 = require("child_process");
|
|
53
54
|
const path = __importStar(require("path"));
|
|
54
55
|
const os = __importStar(require("os"));
|
|
@@ -87,6 +88,19 @@ function truncateText(text, maxLength) {
|
|
|
87
88
|
return text;
|
|
88
89
|
return text.substring(0, maxLength - 3) + '...';
|
|
89
90
|
}
|
|
91
|
+
// Task status config
|
|
92
|
+
const taskStatusConfig = {
|
|
93
|
+
pending: { color: colors.textTertiary, icon: '○' },
|
|
94
|
+
in_progress: { color: colors.accentOrange, icon: '◐' },
|
|
95
|
+
completed: { color: colors.accentGreen, icon: '●' },
|
|
96
|
+
blocked: { color: '#f85149', icon: '✗' },
|
|
97
|
+
};
|
|
98
|
+
const taskPriorityColors = {
|
|
99
|
+
low: colors.textTertiary,
|
|
100
|
+
medium: '#d29922',
|
|
101
|
+
high: colors.accentOrange,
|
|
102
|
+
urgent: '#f85149',
|
|
103
|
+
};
|
|
90
104
|
const FILTER_TYPES = ['all', 'name', 'path', 'ports', 'tags', 'running'];
|
|
91
105
|
const SORT_TYPES = ['name-asc', 'name-desc', 'recent', 'oldest', 'running'];
|
|
92
106
|
const FILTER_LABELS = {
|
|
@@ -115,9 +129,11 @@ const HelpModal = ({ onClose }) => {
|
|
|
115
129
|
react_1.default.createElement(ink_1.Text, null, " "),
|
|
116
130
|
react_1.default.createElement(ink_1.Text, { color: colors.accentCyan }, "View Navigation:"),
|
|
117
131
|
react_1.default.createElement(ink_1.Text, null, " 1 Projects view"),
|
|
118
|
-
react_1.default.createElement(ink_1.Text, null, " 2
|
|
119
|
-
react_1.default.createElement(ink_1.Text, null, " 3
|
|
120
|
-
react_1.default.createElement(ink_1.Text, null, " 4
|
|
132
|
+
react_1.default.createElement(ink_1.Text, null, " 2 Tasks view (requires selected project)"),
|
|
133
|
+
react_1.default.createElement(ink_1.Text, null, " 3 Agents view (requires selected project)"),
|
|
134
|
+
react_1.default.createElement(ink_1.Text, null, " 4 Processes view"),
|
|
135
|
+
react_1.default.createElement(ink_1.Text, null, " 5 Workspaces view"),
|
|
136
|
+
react_1.default.createElement(ink_1.Text, null, " 6 Settings"),
|
|
121
137
|
react_1.default.createElement(ink_1.Text, null, " T Toggle terminal output panel"),
|
|
122
138
|
react_1.default.createElement(ink_1.Text, null, " "),
|
|
123
139
|
react_1.default.createElement(ink_1.Text, { color: colors.accentCyan }, "Projects View - Navigation:"),
|
|
@@ -464,7 +480,7 @@ const ProjectDetailsComponent = ({ project, runningProcesses, isFocused, editing
|
|
|
464
480
|
}
|
|
465
481
|
}
|
|
466
482
|
}
|
|
467
|
-
catch { }
|
|
483
|
+
catch (e) { /* Ignore parsing or file read errors */ }
|
|
468
484
|
}, [project]);
|
|
469
485
|
if (!project) {
|
|
470
486
|
return (react_1.default.createElement(ink_1.Box, { flexDirection: "column", flexGrow: 1, borderStyle: "round", borderColor: isFocused ? colors.accentCyan : colors.borderColor, padding: 1 },
|
|
@@ -830,6 +846,21 @@ const App = () => {
|
|
|
830
846
|
const settingsBrowserOptions = [
|
|
831
847
|
'chrome', 'firefox', 'safari', 'edge', 'custom',
|
|
832
848
|
];
|
|
849
|
+
// Agents state
|
|
850
|
+
const [agents, setAgents] = (0, react_1.useState)([]);
|
|
851
|
+
const [selectedAgentIndex, setSelectedAgentIndex] = (0, react_1.useState)(0);
|
|
852
|
+
const [runningAgentsList, setRunningAgentsList] = (0, react_1.useState)([]);
|
|
853
|
+
const [showAddAgentModal, setShowAddAgentModal] = (0, react_1.useState)(false);
|
|
854
|
+
const [editingAgent, setEditingAgent] = (0, react_1.useState)(null);
|
|
855
|
+
const [newAgentName, setNewAgentName] = (0, react_1.useState)('');
|
|
856
|
+
const [newAgentCliType, setNewAgentCliType] = (0, react_1.useState)('claude');
|
|
857
|
+
const [newAgentCliTypeIndex, setNewAgentCliTypeIndex] = (0, react_1.useState)(0);
|
|
858
|
+
const [agentInputField, setAgentInputField] = (0, react_1.useState)('name');
|
|
859
|
+
const [newAgentModel, setNewAgentModel] = (0, react_1.useState)('');
|
|
860
|
+
const [newAgentApiKey, setNewAgentApiKey] = (0, react_1.useState)('');
|
|
861
|
+
// Tasks state
|
|
862
|
+
const [tasks, setTasks] = (0, react_1.useState)([]);
|
|
863
|
+
const [selectedTaskIdx, setSelectedTaskIdx] = (0, react_1.useState)(0);
|
|
833
864
|
// Get terminal dimensions
|
|
834
865
|
const terminalHeight = process.stdout.rows || 24;
|
|
835
866
|
const availableHeight = terminalHeight - 4; // Subtract status bar (increased for view indicator)
|
|
@@ -848,12 +879,20 @@ const App = () => {
|
|
|
848
879
|
catch {
|
|
849
880
|
// Use defaults
|
|
850
881
|
}
|
|
851
|
-
// Refresh running processes
|
|
882
|
+
// Refresh running processes, git branches, and running agents every 5 seconds
|
|
852
883
|
const interval = setInterval(() => {
|
|
853
884
|
loadRunningProcesses();
|
|
885
|
+
loadRunningAgentsList();
|
|
854
886
|
}, 5000);
|
|
855
887
|
return () => clearInterval(interval);
|
|
856
888
|
}, []);
|
|
889
|
+
// Load agents when switching to agents view or when selected project changes
|
|
890
|
+
(0, react_1.useEffect)(() => {
|
|
891
|
+
const currentProject = projects.length > 0 ? projects[selectedIndex] : null;
|
|
892
|
+
if (currentView === 'agents' && currentProject) {
|
|
893
|
+
loadAgentsForProject(currentProject.id);
|
|
894
|
+
}
|
|
895
|
+
}, [currentView, projects, selectedIndex]);
|
|
857
896
|
// Load git branches when projects change
|
|
858
897
|
(0, react_1.useEffect)(() => {
|
|
859
898
|
if (allProjects.length > 0) {
|
|
@@ -882,12 +921,12 @@ const App = () => {
|
|
|
882
921
|
setDetailsScrollOffset(0); // Reset scroll when switching projects
|
|
883
922
|
setDetailSelectedScript(0); // Reset selected script
|
|
884
923
|
}, [selectedIndex]);
|
|
885
|
-
// Load workspaces when switching to workspaces view
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
}, [currentView]);
|
|
924
|
+
// Load workspaces when switching to workspaces view (legacy - kept for future use)
|
|
925
|
+
// useEffect(() => {
|
|
926
|
+
// if (currentView === 'workspaces' && workspaces.length === 0) {
|
|
927
|
+
// loadWorkspacesFromApi();
|
|
928
|
+
// }
|
|
929
|
+
// }, [currentView]);
|
|
891
930
|
// Update scroll offset when selected index changes
|
|
892
931
|
(0, react_1.useEffect)(() => {
|
|
893
932
|
const visibleHeight = Math.max(1, availableHeight - 3);
|
|
@@ -917,6 +956,27 @@ const App = () => {
|
|
|
917
956
|
setAllTags([]);
|
|
918
957
|
}
|
|
919
958
|
};
|
|
959
|
+
const loadAgentsForProject = (projectId) => {
|
|
960
|
+
try {
|
|
961
|
+
const projectAgents = (0, agent_runner_1.getAgentsByProject)(projectId);
|
|
962
|
+
setAgents(projectAgents);
|
|
963
|
+
if (selectedAgentIndex >= projectAgents.length) {
|
|
964
|
+
setSelectedAgentIndex(Math.max(0, projectAgents.length - 1));
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
catch (error) {
|
|
968
|
+
setAgents([]);
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
const loadRunningAgentsList = () => {
|
|
972
|
+
try {
|
|
973
|
+
const running = (0, agent_runner_1.getRunningAgents)();
|
|
974
|
+
setRunningAgentsList(running);
|
|
975
|
+
}
|
|
976
|
+
catch (error) {
|
|
977
|
+
setRunningAgentsList([]);
|
|
978
|
+
}
|
|
979
|
+
};
|
|
920
980
|
const loadProjects = () => {
|
|
921
981
|
const loadedProjects = (0, core_bridge_1.getAllProjects)();
|
|
922
982
|
setAllProjects(loadedProjects);
|
|
@@ -1307,64 +1367,139 @@ const App = () => {
|
|
|
1307
1367
|
}
|
|
1308
1368
|
return;
|
|
1309
1369
|
}
|
|
1310
|
-
//
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1370
|
+
// Tasks view navigation is handled in renderTasksView
|
|
1371
|
+
// Handle navigation in agents view
|
|
1372
|
+
if (currentView === 'agents') {
|
|
1373
|
+
// Handle add agent modal
|
|
1374
|
+
if (showAddAgentModal) {
|
|
1375
|
+
if (key.escape) {
|
|
1376
|
+
setShowAddAgentModal(false);
|
|
1377
|
+
setNewAgentName('');
|
|
1378
|
+
setNewAgentModel('');
|
|
1379
|
+
setNewAgentApiKey('');
|
|
1380
|
+
setNewAgentCliTypeIndex(0);
|
|
1381
|
+
setAgentInputField('name');
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
if (key.tab) {
|
|
1385
|
+
// Cycle through input fields
|
|
1386
|
+
const fields = ['name', 'cli_type', 'model', 'api_key'];
|
|
1387
|
+
const currentIdx = fields.indexOf(agentInputField);
|
|
1388
|
+
setAgentInputField(fields[(currentIdx + 1) % fields.length]);
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
if (agentInputField === 'cli_type') {
|
|
1392
|
+
if (key.upArrow || input === 'k') {
|
|
1393
|
+
setNewAgentCliTypeIndex(prev => Math.max(0, prev - 1));
|
|
1394
|
+
setNewAgentCliType(agent_runner_1.VALID_CLI_TYPES[Math.max(0, newAgentCliTypeIndex - 1)]);
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
if (key.downArrow || input === 'j') {
|
|
1398
|
+
setNewAgentCliTypeIndex(prev => Math.min(agent_runner_1.VALID_CLI_TYPES.length - 1, prev + 1));
|
|
1399
|
+
setNewAgentCliType(agent_runner_1.VALID_CLI_TYPES[Math.min(agent_runner_1.VALID_CLI_TYPES.length - 1, newAgentCliTypeIndex + 1)]);
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
if (key.return && agentInputField === 'api_key' && newAgentName.trim()) {
|
|
1404
|
+
// Create agent
|
|
1405
|
+
if (selectedProject) {
|
|
1406
|
+
const agent = (0, agent_runner_1.createAgent)(selectedProject.id, {
|
|
1407
|
+
name: newAgentName.trim(),
|
|
1408
|
+
cli_type: newAgentCliType,
|
|
1409
|
+
model: newAgentModel.trim() || null,
|
|
1410
|
+
api_key: newAgentApiKey.trim() || null,
|
|
1411
|
+
});
|
|
1412
|
+
if (agent) {
|
|
1413
|
+
loadAgentsForProject(selectedProject.id);
|
|
1414
|
+
setShowAddAgentModal(false);
|
|
1415
|
+
setNewAgentName('');
|
|
1416
|
+
setNewAgentModel('');
|
|
1417
|
+
setNewAgentApiKey('');
|
|
1418
|
+
setNewAgentCliTypeIndex(0);
|
|
1419
|
+
setAgentInputField('name');
|
|
1420
|
+
}
|
|
1421
|
+
else {
|
|
1422
|
+
setError('Failed to create agent');
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
// Handle text input
|
|
1428
|
+
if (agentInputField === 'name') {
|
|
1429
|
+
if (key.backspace || key.delete) {
|
|
1430
|
+
setNewAgentName(prev => prev.slice(0, -1));
|
|
1431
|
+
}
|
|
1432
|
+
else if (input && input.length === 1 && !key.ctrl && !key.meta) {
|
|
1433
|
+
setNewAgentName(prev => prev + input);
|
|
1434
|
+
}
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
if (agentInputField === 'model') {
|
|
1438
|
+
if (key.backspace || key.delete) {
|
|
1439
|
+
setNewAgentModel(prev => prev.slice(0, -1));
|
|
1440
|
+
}
|
|
1441
|
+
else if (input && input.length === 1 && !key.ctrl && !key.meta) {
|
|
1442
|
+
setNewAgentModel(prev => prev + input);
|
|
1443
|
+
}
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
if (agentInputField === 'api_key') {
|
|
1447
|
+
if (key.backspace || key.delete) {
|
|
1448
|
+
setNewAgentApiKey(prev => prev.slice(0, -1));
|
|
1449
|
+
}
|
|
1450
|
+
else if (input && input.length === 1 && !key.ctrl && !key.meta) {
|
|
1451
|
+
setNewAgentApiKey(prev => prev + input);
|
|
1452
|
+
}
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1318
1455
|
return;
|
|
1319
1456
|
}
|
|
1320
|
-
|
|
1321
|
-
// Handle navigation in processes view
|
|
1322
|
-
if (currentView === 'processes') {
|
|
1457
|
+
// Navigation
|
|
1323
1458
|
if (key.upArrow || input === 'k') {
|
|
1324
|
-
|
|
1459
|
+
setSelectedAgentIndex(prev => Math.max(0, prev - 1));
|
|
1325
1460
|
return;
|
|
1326
1461
|
}
|
|
1327
1462
|
if (key.downArrow || input === 'j') {
|
|
1328
|
-
|
|
1463
|
+
setSelectedAgentIndex(prev => Math.min(agents.length - 1, prev + 1));
|
|
1329
1464
|
return;
|
|
1330
1465
|
}
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1466
|
+
// Add agent
|
|
1467
|
+
if (input === 'a') {
|
|
1468
|
+
setShowAddAgentModal(true);
|
|
1469
|
+
setAgentInputField('name');
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
// Launch agent
|
|
1473
|
+
if (key.return || input === 'l') {
|
|
1474
|
+
const agent = agents[selectedAgentIndex];
|
|
1475
|
+
if (agent && selectedProject) {
|
|
1476
|
+
const success = (0, agent_runner_1.launchAgentInTerminal)(agent, selectedProject.path);
|
|
1477
|
+
if (success) {
|
|
1478
|
+
setError(null);
|
|
1343
1479
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
1480
|
+
else {
|
|
1481
|
+
setError('Failed to launch agent');
|
|
1347
1482
|
}
|
|
1348
|
-
}
|
|
1483
|
+
}
|
|
1349
1484
|
return;
|
|
1350
1485
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
await (0, script_runner_1.stopScript)(proc.pid);
|
|
1359
|
-
}
|
|
1360
|
-
await loadRunningProcesses();
|
|
1361
|
-
setIsLoading(false);
|
|
1486
|
+
// Delete agent
|
|
1487
|
+
if (input === 'd') {
|
|
1488
|
+
const agent = agents[selectedAgentIndex];
|
|
1489
|
+
if (agent) {
|
|
1490
|
+
const success = (0, agent_runner_1.deleteAgent)(agent.id);
|
|
1491
|
+
if (success && selectedProject) {
|
|
1492
|
+
loadAgentsForProject(selectedProject.id);
|
|
1362
1493
|
}
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
1494
|
+
else {
|
|
1495
|
+
setError('Failed to delete agent');
|
|
1366
1496
|
}
|
|
1367
|
-
}
|
|
1497
|
+
}
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
// Back to projects
|
|
1501
|
+
if (key.escape) {
|
|
1502
|
+
setCurrentView('projects');
|
|
1368
1503
|
return;
|
|
1369
1504
|
}
|
|
1370
1505
|
}
|
|
@@ -1415,14 +1550,28 @@ const App = () => {
|
|
|
1415
1550
|
return;
|
|
1416
1551
|
}
|
|
1417
1552
|
if (input === '2') {
|
|
1418
|
-
setCurrentView('
|
|
1553
|
+
setCurrentView('tasks');
|
|
1419
1554
|
return;
|
|
1420
1555
|
}
|
|
1421
1556
|
if (input === '3') {
|
|
1422
|
-
|
|
1557
|
+
if (selectedProject) {
|
|
1558
|
+
setCurrentView('agents');
|
|
1559
|
+
loadAgentsForProject(selectedProject.id);
|
|
1560
|
+
}
|
|
1561
|
+
else {
|
|
1562
|
+
setError('Select a project first to manage agents');
|
|
1563
|
+
}
|
|
1423
1564
|
return;
|
|
1424
1565
|
}
|
|
1425
1566
|
if (input === '4') {
|
|
1567
|
+
setCurrentView('processes');
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
if (input === '5') {
|
|
1571
|
+
setCurrentView('workspaces');
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
if (input === '6') {
|
|
1426
1575
|
setCurrentView('settings');
|
|
1427
1576
|
return;
|
|
1428
1577
|
}
|
|
@@ -1940,21 +2089,182 @@ const App = () => {
|
|
|
1940
2089
|
react_1.default.createElement(ink_1.Text, null, " "),
|
|
1941
2090
|
react_1.default.createElement(ink_1.Text, { color: colors.textTertiary }, "Tab: switch section | \u2191\u2193/jk: select | Space/Enter: choose")));
|
|
1942
2091
|
};
|
|
2092
|
+
// Load tasks when switching to tasks view
|
|
2093
|
+
(0, react_1.useEffect)(() => {
|
|
2094
|
+
if (currentView === 'tasks' && selectedProject) {
|
|
2095
|
+
loadTasksForProject();
|
|
2096
|
+
}
|
|
2097
|
+
}, [currentView, selectedProject]);
|
|
2098
|
+
const loadTasksForProject = async () => {
|
|
2099
|
+
if (!selectedProject)
|
|
2100
|
+
return;
|
|
2101
|
+
try {
|
|
2102
|
+
const ports = [38124, 38125, 38126];
|
|
2103
|
+
let apiBaseUrl = '';
|
|
2104
|
+
for (const port of ports) {
|
|
2105
|
+
try {
|
|
2106
|
+
const res = await fetch(`http://localhost:${port}/health`, { signal: AbortSignal.timeout(500) });
|
|
2107
|
+
if (res.ok) {
|
|
2108
|
+
apiBaseUrl = `http://localhost:${port}/api`;
|
|
2109
|
+
break;
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
catch (e) { /* Ignore API port check errors */ }
|
|
2113
|
+
}
|
|
2114
|
+
if (!apiBaseUrl)
|
|
2115
|
+
return;
|
|
2116
|
+
// Get todo lists
|
|
2117
|
+
const listsRes = await fetch(`${apiBaseUrl}/projects/${selectedProject.id}/todo-lists`);
|
|
2118
|
+
const lists = listsRes.ok ? (await listsRes.json()) : [];
|
|
2119
|
+
// Get tasks for each list
|
|
2120
|
+
const allTasks = [];
|
|
2121
|
+
for (const list of lists) {
|
|
2122
|
+
const tasksRes = await fetch(`${apiBaseUrl}/todo-lists/${list.id}/tasks`);
|
|
2123
|
+
if (tasksRes.ok) {
|
|
2124
|
+
const listTasks = (await tasksRes.json());
|
|
2125
|
+
allTasks.push(...listTasks);
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
catch (e) { /* Ignore task loading errors */ }
|
|
2130
|
+
};
|
|
2131
|
+
// Render Tasks view
|
|
2132
|
+
const renderTasksView = () => {
|
|
2133
|
+
if (!selectedProject) {
|
|
2134
|
+
return (react_1.default.createElement(ink_1.Box, { flexDirection: "column", padding: 2 },
|
|
2135
|
+
react_1.default.createElement(ink_1.Text, { bold: true, color: colors.accentCyan }, "Tasks"),
|
|
2136
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2137
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textTertiary }, "Select a project first to view tasks")));
|
|
2138
|
+
}
|
|
2139
|
+
return (react_1.default.createElement(ink_1.Box, { flexDirection: "column", padding: 1, height: availableHeight },
|
|
2140
|
+
react_1.default.createElement(ink_1.Text, { bold: true, color: colors.accentCyan },
|
|
2141
|
+
"Tasks for ",
|
|
2142
|
+
selectedProject.name,
|
|
2143
|
+
" (",
|
|
2144
|
+
tasks.length,
|
|
2145
|
+
")"),
|
|
2146
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2147
|
+
tasks.length === 0 ? (react_1.default.createElement(ink_1.Box, { flexDirection: "column" },
|
|
2148
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textTertiary }, "No tasks found"),
|
|
2149
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2150
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textSecondary }, "Press 'a' to add a task"))) : (react_1.default.createElement(ink_1.Box, { flexDirection: "column" }, tasks.map((task, idx) => {
|
|
2151
|
+
const isSelected = idx === selectedTaskIdx;
|
|
2152
|
+
const cfg = taskStatusConfig[task.status];
|
|
2153
|
+
return (react_1.default.createElement(ink_1.Box, { key: task.id },
|
|
2154
|
+
react_1.default.createElement(ink_1.Text, { color: isSelected ? colors.accentCyan : colors.textPrimary, bold: isSelected },
|
|
2155
|
+
isSelected ? '▶ ' : ' ',
|
|
2156
|
+
react_1.default.createElement(ink_1.Text, { color: cfg.color }, cfg.icon),
|
|
2157
|
+
" ",
|
|
2158
|
+
truncateText(task.title, 40)),
|
|
2159
|
+
task.worktree_path && react_1.default.createElement(ink_1.Text, { color: colors.accentGreen }, " \uD83C\uDF3F")));
|
|
2160
|
+
}))),
|
|
2161
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2162
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textTertiary }, "\u2191\u2193/jk: navigate | a: add task | Space: toggle | d: delete")));
|
|
2163
|
+
};
|
|
2164
|
+
// Render Agents view
|
|
2165
|
+
const renderAgentsView = () => {
|
|
2166
|
+
const selectedAgent = agents[selectedAgentIndex];
|
|
2167
|
+
const isAgentRunning = selectedAgent
|
|
2168
|
+
? runningAgentsList.some(r => r.agentId === selectedAgent.id)
|
|
2169
|
+
: false;
|
|
2170
|
+
return (react_1.default.createElement(ink_1.Box, { flexDirection: "column", padding: 1, height: availableHeight },
|
|
2171
|
+
showAddAgentModal && (react_1.default.createElement(ink_1.Box, { flexDirection: "column", borderStyle: "round", borderColor: colors.accentCyan, padding: 1, width: 60 },
|
|
2172
|
+
react_1.default.createElement(ink_1.Text, { bold: true, color: colors.accentCyan }, "Add New Agent"),
|
|
2173
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2174
|
+
react_1.default.createElement(ink_1.Box, null,
|
|
2175
|
+
react_1.default.createElement(ink_1.Text, { color: agentInputField === 'name' ? colors.accentCyan : colors.textSecondary },
|
|
2176
|
+
"Name: ",
|
|
2177
|
+
agentInputField === 'name' ? '▶ ' : ' '),
|
|
2178
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textPrimary }, newAgentName || '_')),
|
|
2179
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2180
|
+
react_1.default.createElement(ink_1.Text, { color: agentInputField === 'cli_type' ? colors.accentCyan : colors.textSecondary },
|
|
2181
|
+
"CLI Type: ",
|
|
2182
|
+
agentInputField === 'cli_type' ? '▶' : ''),
|
|
2183
|
+
agent_runner_1.VALID_CLI_TYPES.map((cliType, idx) => (react_1.default.createElement(ink_1.Text, { key: cliType, color: idx === newAgentCliTypeIndex ? colors.accentGreen : colors.textTertiary },
|
|
2184
|
+
idx === newAgentCliTypeIndex ? ' ● ' : ' ○ ',
|
|
2185
|
+
agent_runner_1.CLI_DISPLAY_NAMES[cliType]))),
|
|
2186
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2187
|
+
react_1.default.createElement(ink_1.Box, null,
|
|
2188
|
+
react_1.default.createElement(ink_1.Text, { color: agentInputField === 'model' ? colors.accentCyan : colors.textSecondary },
|
|
2189
|
+
"Model (optional): ",
|
|
2190
|
+
agentInputField === 'model' ? '▶ ' : ' '),
|
|
2191
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textPrimary }, newAgentModel || '_')),
|
|
2192
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2193
|
+
react_1.default.createElement(ink_1.Box, null,
|
|
2194
|
+
react_1.default.createElement(ink_1.Text, { color: agentInputField === 'api_key' ? colors.accentCyan : colors.textSecondary },
|
|
2195
|
+
"API Key (optional): ",
|
|
2196
|
+
agentInputField === 'api_key' ? '▶ ' : ' '),
|
|
2197
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textPrimary }, newAgentApiKey ? '*'.repeat(Math.min(newAgentApiKey.length, 20)) : '_')),
|
|
2198
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2199
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textTertiary }, "Tab: next field | \u2191\u2193: select CLI | Enter: create | Esc: cancel"))),
|
|
2200
|
+
!showAddAgentModal && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
2201
|
+
react_1.default.createElement(ink_1.Text, { bold: true, color: colors.accentCyan },
|
|
2202
|
+
"Agents for ",
|
|
2203
|
+
selectedProject?.name || 'No Project',
|
|
2204
|
+
" (",
|
|
2205
|
+
agents.length,
|
|
2206
|
+
")"),
|
|
2207
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2208
|
+
agents.length === 0 ? (react_1.default.createElement(ink_1.Box, { flexDirection: "column" },
|
|
2209
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textTertiary }, "No agents configured for this project."),
|
|
2210
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2211
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textSecondary }, "Press 'a' to add an agent."))) : (react_1.default.createElement(ink_1.Box, { flexDirection: "row", height: availableHeight - 6 },
|
|
2212
|
+
react_1.default.createElement(ink_1.Box, { flexDirection: "column", width: "40%", borderStyle: "round", borderColor: colors.borderColor, padding: 1 }, agents.map((agent, index) => {
|
|
2213
|
+
const isSelected = index === selectedAgentIndex;
|
|
2214
|
+
const running = runningAgentsList.some(r => r.agentId === agent.id);
|
|
2215
|
+
return (react_1.default.createElement(ink_1.Box, { key: agent.id },
|
|
2216
|
+
react_1.default.createElement(ink_1.Text, { color: isSelected ? colors.accentCyan : colors.textPrimary, bold: isSelected },
|
|
2217
|
+
isSelected ? '▶ ' : ' ',
|
|
2218
|
+
running ? '● ' : '○ ',
|
|
2219
|
+
truncateText(agent.name, 25))));
|
|
2220
|
+
})),
|
|
2221
|
+
react_1.default.createElement(ink_1.Box, { width: 1 }),
|
|
2222
|
+
react_1.default.createElement(ink_1.Box, { flexDirection: "column", width: "60%", borderStyle: "round", borderColor: colors.borderColor, padding: 1 }, selectedAgent && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
2223
|
+
react_1.default.createElement(ink_1.Text, { bold: true, color: colors.accentCyan }, selectedAgent.name),
|
|
2224
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2225
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textSecondary },
|
|
2226
|
+
"Type: ",
|
|
2227
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textPrimary }, agent_runner_1.CLI_DISPLAY_NAMES[selectedAgent.cli_type])),
|
|
2228
|
+
selectedAgent.model && (react_1.default.createElement(ink_1.Text, { color: colors.textSecondary },
|
|
2229
|
+
"Model: ",
|
|
2230
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textPrimary }, selectedAgent.model))),
|
|
2231
|
+
selectedAgent.api_key && (react_1.default.createElement(ink_1.Text, { color: colors.textSecondary },
|
|
2232
|
+
"API Key: ",
|
|
2233
|
+
react_1.default.createElement(ink_1.Text, { color: colors.accentGreen }, "configured"))),
|
|
2234
|
+
selectedAgent.system_prompt && (react_1.default.createElement(ink_1.Text, { color: colors.textSecondary },
|
|
2235
|
+
"System Prompt: ",
|
|
2236
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textPrimary }, truncateText(selectedAgent.system_prompt, 40)))),
|
|
2237
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2238
|
+
react_1.default.createElement(ink_1.Text, { color: isAgentRunning ? colors.accentGreen : colors.textTertiary },
|
|
2239
|
+
"Status: ",
|
|
2240
|
+
isAgentRunning ? 'Running' : 'Stopped')))))),
|
|
2241
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2242
|
+
react_1.default.createElement(ink_1.Text, { color: colors.textTertiary }, "\u2191\u2193/jk: navigate | a: add agent | Enter/l: launch | d: delete | Esc: back to projects")))));
|
|
2243
|
+
};
|
|
1943
2244
|
return (react_1.default.createElement(ink_1.Box, { flexDirection: "column", height: terminalHeight },
|
|
1944
2245
|
react_1.default.createElement(ink_1.Box, { paddingX: 1, height: 1 },
|
|
1945
2246
|
react_1.default.createElement(ink_1.Text, { color: currentView === 'projects' ? colors.accentCyan : colors.textTertiary }, "[1] Projects"),
|
|
1946
2247
|
react_1.default.createElement(ink_1.Text, null, " "),
|
|
1947
|
-
react_1.default.createElement(ink_1.Text, { color: currentView === '
|
|
2248
|
+
react_1.default.createElement(ink_1.Text, { color: currentView === 'tasks' ? colors.accentCyan : colors.textTertiary }, "[2] Tasks"),
|
|
2249
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2250
|
+
react_1.default.createElement(ink_1.Text, { color: currentView === 'agents' ? colors.accentCyan : colors.textTertiary }, "[3] Agents"),
|
|
1948
2251
|
react_1.default.createElement(ink_1.Text, null, " "),
|
|
1949
|
-
react_1.default.createElement(ink_1.Text, { color: currentView === 'processes' ? colors.accentCyan : colors.textTertiary }, "[
|
|
2252
|
+
react_1.default.createElement(ink_1.Text, { color: currentView === 'processes' ? colors.accentCyan : colors.textTertiary }, "[4] Processes"),
|
|
1950
2253
|
react_1.default.createElement(ink_1.Text, null, " "),
|
|
1951
|
-
react_1.default.createElement(ink_1.Text, { color: currentView === '
|
|
1952
|
-
|
|
2254
|
+
react_1.default.createElement(ink_1.Text, { color: currentView === 'workspaces' ? colors.accentCyan : colors.textTertiary }, "[5] Workspaces"),
|
|
2255
|
+
react_1.default.createElement(ink_1.Text, null, " "),
|
|
2256
|
+
react_1.default.createElement(ink_1.Text, { color: currentView === 'settings' ? colors.accentCyan : colors.textTertiary }, "[6] Settings"),
|
|
2257
|
+
runningAgentsList.length > 0 && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
1953
2258
|
react_1.default.createElement(ink_1.Text, null, " | "),
|
|
1954
|
-
react_1.default.createElement(ink_1.Text, { color: colors.accentGreen },
|
|
2259
|
+
react_1.default.createElement(ink_1.Text, { color: colors.accentGreen },
|
|
2260
|
+
"\u25CF ",
|
|
2261
|
+
runningAgentsList.length,
|
|
2262
|
+
" running")))),
|
|
1955
2263
|
currentView === 'projects' && renderProjectsView(),
|
|
1956
|
-
currentView === '
|
|
2264
|
+
currentView === 'tasks' && renderTasksView(),
|
|
2265
|
+
currentView === 'agents' && renderAgentsView(),
|
|
1957
2266
|
currentView === 'processes' && renderProcessesView(),
|
|
2267
|
+
currentView === 'workspaces' && renderWorkspacesView(),
|
|
1958
2268
|
currentView === 'settings' && renderSettingsView(),
|
|
1959
2269
|
react_1.default.createElement(ink_1.Box, { paddingX: 1, borderStyle: "single", borderColor: colors.borderColor, flexShrink: 0, height: 3 },
|
|
1960
2270
|
react_1.default.createElement(StatusBar, { focusedPanel: focusedPanel, selectedProject: selectedProject }))));
|