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.
Files changed (39) hide show
  1. package/dist/agent-runner.d.ts +60 -0
  2. package/dist/agent-runner.js +382 -0
  3. package/dist/api/database.d.ts +38 -1
  4. package/dist/api/database.d.ts.map +1 -1
  5. package/dist/api/database.js +327 -0
  6. package/dist/api/database.js.map +1 -1
  7. package/dist/api/routes/agents.d.ts +4 -0
  8. package/dist/api/routes/agents.d.ts.map +1 -0
  9. package/dist/api/routes/agents.js +375 -0
  10. package/dist/api/routes/agents.js.map +1 -0
  11. package/dist/api/routes/index.d.ts.map +1 -1
  12. package/dist/api/routes/index.js +4 -0
  13. package/dist/api/routes/index.js.map +1 -1
  14. package/dist/api/routes/todos.d.ts +4 -0
  15. package/dist/api/routes/todos.d.ts.map +1 -0
  16. package/dist/api/routes/todos.js +595 -0
  17. package/dist/api/routes/todos.js.map +1 -0
  18. package/dist/api/types.d.ts +67 -0
  19. package/dist/api/types.d.ts.map +1 -1
  20. package/dist/core/database.d.ts +47 -0
  21. package/dist/core/database.js +48 -0
  22. package/dist/core-bridge.d.ts +1 -1
  23. package/dist/electron/core/database.d.ts +47 -0
  24. package/dist/electron/core/database.js +48 -0
  25. package/dist/electron/renderer/assets/index-6afBeDFD.js +66 -0
  26. package/dist/electron/renderer/assets/index-Bd3aFi7B.css +1 -0
  27. package/dist/electron/renderer/index.html +2 -2
  28. package/dist/index.js +6 -175
  29. package/dist/octopus-cli.d.ts +2 -0
  30. package/dist/octopus-cli.js +45 -0
  31. package/dist/octopus-show-tui.d.ts +1 -0
  32. package/dist/octopus-show-tui.js +802 -0
  33. package/dist/octopus-tui.d.ts +1 -0
  34. package/dist/octopus-tui.js +115 -0
  35. package/dist/prxi.js +373 -63
  36. package/dist/prxi.tsx +472 -65
  37. package/package.json +7 -2
  38. package/dist/electron/renderer/assets/index-Cd1mTO3s.js +0 -66
  39. 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 Workspaces view"),
119
- react_1.default.createElement(ink_1.Text, null, " 3 Global processes view"),
120
- react_1.default.createElement(ink_1.Text, null, " 4 Settings"),
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 and git branches every 5 seconds
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
- (0, react_1.useEffect)(() => {
887
- if (currentView === 'workspaces' && workspaces.length === 0) {
888
- loadWorkspacesFromApi();
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
- // Handle navigation in workspaces view
1311
- if (currentView === 'workspaces') {
1312
- if (key.upArrow || input === 'k') {
1313
- setSelectedWorkspaceIndex((prev) => Math.max(0, prev - 1));
1314
- return;
1315
- }
1316
- if (key.downArrow || input === 'j') {
1317
- setSelectedWorkspaceIndex((prev) => Math.min(workspaces.length - 1, prev + 1));
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
- setSelectedProcessIndex((prev) => Math.max(0, prev - 1));
1459
+ setSelectedAgentIndex(prev => Math.max(0, prev - 1));
1325
1460
  return;
1326
1461
  }
1327
1462
  if (key.downArrow || input === 'j') {
1328
- setSelectedProcessIndex((prev) => Math.min(runningProcesses.length - 1, prev + 1));
1463
+ setSelectedAgentIndex(prev => Math.min(agents.length - 1, prev + 1));
1329
1464
  return;
1330
1465
  }
1331
- if (input === 'x' && runningProcesses.length > 0) {
1332
- // Stop the selected process
1333
- const selectedProc = runningProcesses[selectedProcessIndex];
1334
- if (!selectedProc)
1335
- return;
1336
- setIsLoading(true);
1337
- setLoadingMessage(`Stopping process ${selectedProc.pid}...`);
1338
- setTimeout(async () => {
1339
- try {
1340
- await (0, script_runner_1.stopScript)(selectedProc.pid);
1341
- await loadRunningProcesses();
1342
- setIsLoading(false);
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
- catch (err) {
1345
- setIsLoading(false);
1346
- setError(err instanceof Error ? err.message : String(err));
1480
+ else {
1481
+ setError('Failed to launch agent');
1347
1482
  }
1348
- }, 100);
1483
+ }
1349
1484
  return;
1350
1485
  }
1351
- if (input === 'X' && runningProcesses.length > 0) {
1352
- // Stop ALL processes
1353
- setIsLoading(true);
1354
- setLoadingMessage('Stopping all processes...');
1355
- setTimeout(async () => {
1356
- try {
1357
- for (const proc of runningProcesses) {
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
- catch (err) {
1364
- setIsLoading(false);
1365
- setError(err instanceof Error ? err.message : String(err));
1494
+ else {
1495
+ setError('Failed to delete agent');
1366
1496
  }
1367
- }, 100);
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('workspaces');
1553
+ setCurrentView('tasks');
1419
1554
  return;
1420
1555
  }
1421
1556
  if (input === '3') {
1422
- setCurrentView('processes');
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 === 'workspaces' ? colors.accentCyan : colors.textTertiary }, "[2] Workspaces"),
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 }, "[3] Processes"),
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 === 'settings' ? colors.accentCyan : colors.textTertiary }, "[4] Settings"),
1952
- showTerminalPanel && (react_1.default.createElement(react_1.default.Fragment, null,
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 }, "Terminal [T]")))),
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 === 'workspaces' && renderWorkspacesView(),
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 }))));