@mrpatronz/nexusflow 0.1.7 → 0.1.9
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/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +11 -0
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/open.d.ts.map +1 -1
- package/dist/commands/open.js +45 -9
- package/dist/commands/open.js.map +1 -1
- package/dist/core/packer.test.d.ts +2 -0
- package/dist/core/packer.test.d.ts.map +1 -0
- package/dist/core/packer.test.js +83 -0
- package/dist/core/packer.test.js.map +1 -0
- package/dist/gui/assets/index-7IR7ZrSG.css +2 -0
- package/dist/gui/assets/index-BfNp4LNj.js +21 -0
- package/dist/gui/index.html +2 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +153 -14
- package/dist/server.js.map +1 -1
- package/gui/src/App.tsx +283 -145
- package/package.json +1 -1
- package/src/commands/create.ts +13 -0
- package/src/commands/open.ts +38 -6
- package/src/core/packer.test.ts +101 -0
- package/src/server.ts +205 -27
- package/dist/gui/assets/index-DPPCFG2H.css +0 -2
- package/dist/gui/assets/index-io0N2VQx.js +0 -21
- package/gui/src/features/workspace/WorkspaceBuilder.tsx +0 -414
package/gui/src/App.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
ExternalLink,
|
|
10
10
|
Check,
|
|
11
11
|
AlertTriangle,
|
|
12
|
+
AlertCircle,
|
|
12
13
|
FolderOpen,
|
|
13
14
|
ArrowRight,
|
|
14
15
|
ArrowLeft,
|
|
@@ -126,6 +127,13 @@ export default function App() {
|
|
|
126
127
|
const [selectedEditor, setSelectedEditor] = useState<DetectedEditor | null>(null);
|
|
127
128
|
const [creating, setCreating] = useState(false);
|
|
128
129
|
const [createdWorkspace, setCreatedWorkspace] = useState<{ path: string } | null>(null);
|
|
130
|
+
const [creationError, setCreationError] = useState<string | null>(null);
|
|
131
|
+
const [creationSteps, setCreationSteps] = useState<any[]>([
|
|
132
|
+
{ id: 'worktrees', name: 'Create Git Worktrees', status: 'pending', message: 'Waiting...' },
|
|
133
|
+
{ id: 'analysis', name: 'Analyze Repositories', status: 'pending', message: 'Waiting...' },
|
|
134
|
+
{ id: 'context', name: 'Generate AI Context Files', status: 'pending', message: 'Waiting...' },
|
|
135
|
+
{ id: 'pack', name: 'Pack Codebase Context', status: 'pending', message: 'Waiting...' },
|
|
136
|
+
]);
|
|
129
137
|
|
|
130
138
|
// Resumption Commands State
|
|
131
139
|
const [testCommand, setTestCommand] = useState('npm run test');
|
|
@@ -561,6 +569,16 @@ export default function App() {
|
|
|
561
569
|
const handleCreateWorkspace = async () => {
|
|
562
570
|
if (!branchName || selectedRepos.length === 0) return;
|
|
563
571
|
setCreating(true);
|
|
572
|
+
setCreationError(null);
|
|
573
|
+
|
|
574
|
+
// Reset steps to pending
|
|
575
|
+
setCreationSteps([
|
|
576
|
+
{ id: 'worktrees', name: 'Create Git Worktrees', status: 'pending', message: 'Waiting...' },
|
|
577
|
+
{ id: 'analysis', name: 'Analyze Repositories', status: 'pending', message: 'Waiting...' },
|
|
578
|
+
{ id: 'context', name: 'Generate AI Context Files', status: 'pending', message: 'Waiting...' },
|
|
579
|
+
{ id: 'pack', name: 'Pack Codebase Context', status: 'pending', message: 'Waiting...' },
|
|
580
|
+
]);
|
|
581
|
+
|
|
564
582
|
try {
|
|
565
583
|
const res = await fetch(`${API_BASE}/api/workspace`, {
|
|
566
584
|
method: 'POST',
|
|
@@ -579,32 +597,62 @@ export default function App() {
|
|
|
579
597
|
});
|
|
580
598
|
const data = await res.json();
|
|
581
599
|
if (res.ok && data.success) {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
600
|
+
const jobId = data.jobId;
|
|
601
|
+
|
|
602
|
+
// Establish EventSource SSE connection
|
|
603
|
+
const eventSource = new EventSource(`${API_BASE}/api/workspace/create-stream/${encodeURIComponent(jobId)}`);
|
|
604
|
+
|
|
605
|
+
eventSource.addEventListener('progress', (e) => {
|
|
606
|
+
try {
|
|
607
|
+
const job = JSON.parse(e.data);
|
|
608
|
+
if (job.steps) {
|
|
609
|
+
setCreationSteps(job.steps);
|
|
610
|
+
}
|
|
611
|
+
if (job.status === 'completed') {
|
|
612
|
+
eventSource.close();
|
|
613
|
+
setCreatedWorkspace({ path: job.workspacePath });
|
|
614
|
+
setActiveStep(3);
|
|
615
|
+
setCreating(false);
|
|
616
|
+
fetchWorkspaces();
|
|
617
|
+
|
|
618
|
+
if (selectedEditor) {
|
|
619
|
+
if (isVsCode) {
|
|
620
|
+
window.parent.postMessage({ type: 'openWorkspaceFolder', workspacePath: job.workspacePath }, '*');
|
|
621
|
+
} else {
|
|
622
|
+
fetch(`${API_BASE}/api/open-editor`, {
|
|
623
|
+
method: 'POST',
|
|
624
|
+
headers: { 'Content-Type': 'application/json' },
|
|
625
|
+
body: JSON.stringify({
|
|
626
|
+
workspacePath: job.workspacePath,
|
|
627
|
+
command: selectedEditor.command,
|
|
628
|
+
}),
|
|
629
|
+
}).catch(console.error);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
} else if (job.status === 'failed') {
|
|
633
|
+
eventSource.close();
|
|
634
|
+
setCreating(false);
|
|
635
|
+
setCreationError(job.error || 'Failed to create workspace');
|
|
636
|
+
}
|
|
637
|
+
} catch (err) {
|
|
638
|
+
console.error('Failed to parse SSE data:', err);
|
|
598
639
|
}
|
|
599
|
-
}
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
eventSource.onerror = (err) => {
|
|
643
|
+
console.error('SSE Error:', err);
|
|
644
|
+
eventSource.close();
|
|
645
|
+
setCreating(false);
|
|
646
|
+
setCreationError('Connection lost while building workspace.');
|
|
647
|
+
};
|
|
600
648
|
} else {
|
|
601
|
-
|
|
649
|
+
setCreating(false);
|
|
650
|
+
setCreationError(data.error || 'Failed to initialize workspace build');
|
|
602
651
|
}
|
|
603
652
|
} catch (e) {
|
|
604
653
|
console.error(e);
|
|
605
|
-
alert('Network error when creating workspace.');
|
|
606
|
-
} finally {
|
|
607
654
|
setCreating(false);
|
|
655
|
+
setCreationError('Network error when creating workspace.');
|
|
608
656
|
}
|
|
609
657
|
};
|
|
610
658
|
|
|
@@ -1374,145 +1422,235 @@ Core Instructions:
|
|
|
1374
1422
|
{/* Step 2: AI & Editor Settings */}
|
|
1375
1423
|
{activeStep === 2 && (
|
|
1376
1424
|
<div className="bg-[#111827]/40 border border-gray-800/80 rounded-xl p-8 shadow-xl backdrop-blur-sm">
|
|
1377
|
-
|
|
1378
|
-
<
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1425
|
+
{creating ? (
|
|
1426
|
+
<div className="flex flex-col items-center py-6">
|
|
1427
|
+
<h3 className="text-lg font-bold text-white mb-2 flex items-center gap-2.5">
|
|
1428
|
+
<RefreshCw className="animate-spin text-indigo-400" size={20} />
|
|
1429
|
+
Building Workspace...
|
|
1430
|
+
</h3>
|
|
1431
|
+
<p className="text-xs text-gray-400 mb-8">
|
|
1432
|
+
Setting up your multi-repo workspace. This will take a moment.
|
|
1433
|
+
</p>
|
|
1434
|
+
|
|
1435
|
+
<div className="w-full max-w-md space-y-4">
|
|
1436
|
+
{creationSteps.map((step) => {
|
|
1437
|
+
const isPending = step.status === 'pending';
|
|
1438
|
+
const isRunning = step.status === 'running';
|
|
1439
|
+
const isCompleted = step.status === 'completed';
|
|
1440
|
+
const isFailed = step.status === 'failed';
|
|
1441
|
+
|
|
1442
|
+
return (
|
|
1443
|
+
<div
|
|
1444
|
+
key={step.id}
|
|
1445
|
+
className={`flex items-start gap-4 p-4 rounded-xl border transition-all duration-300 ${
|
|
1446
|
+
isRunning
|
|
1447
|
+
? 'bg-indigo-500/10 border-indigo-500/50 shadow-md shadow-indigo-500/5'
|
|
1448
|
+
: isCompleted
|
|
1449
|
+
? 'bg-emerald-500/5 border-emerald-500/20 opacity-80'
|
|
1450
|
+
: isFailed
|
|
1451
|
+
? 'bg-rose-500/5 border-rose-500/30'
|
|
1452
|
+
: 'bg-gray-900/20 border-gray-800/40 opacity-40'
|
|
1453
|
+
}`}
|
|
1454
|
+
>
|
|
1455
|
+
<div className="mt-0.5">
|
|
1456
|
+
{isRunning && (
|
|
1457
|
+
<div className="relative flex h-5 w-5 items-center justify-center">
|
|
1458
|
+
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-indigo-400 opacity-75"></span>
|
|
1459
|
+
<RefreshCw className="animate-spin text-indigo-400 relative" size={16} />
|
|
1460
|
+
</div>
|
|
1461
|
+
)}
|
|
1462
|
+
{isCompleted && (
|
|
1463
|
+
<div className="h-5 w-5 rounded-full bg-emerald-500/20 border border-emerald-500/40 flex items-center justify-center text-emerald-400">
|
|
1464
|
+
<Check size={12} />
|
|
1465
|
+
</div>
|
|
1466
|
+
)}
|
|
1467
|
+
{isFailed && (
|
|
1468
|
+
<div className="h-5 w-5 rounded-full bg-rose-500/20 border border-rose-500/40 flex items-center justify-center text-rose-400">
|
|
1469
|
+
<AlertTriangle size={12} />
|
|
1470
|
+
</div>
|
|
1471
|
+
)}
|
|
1472
|
+
{isPending && (
|
|
1473
|
+
<div className="h-5 w-5 rounded-full border-2 border-gray-800 flex items-center justify-center text-gray-600">
|
|
1474
|
+
<div className="w-1.5 h-1.5 rounded-full bg-gray-800"></div>
|
|
1475
|
+
</div>
|
|
1476
|
+
)}
|
|
1477
|
+
</div>
|
|
1478
|
+
<div className="flex-1 min-w-0">
|
|
1479
|
+
<h4 className={`text-sm font-bold truncate ${
|
|
1480
|
+
isRunning ? 'text-indigo-400' : isCompleted ? 'text-emerald-400' : isFailed ? 'text-rose-400' : 'text-gray-500'
|
|
1481
|
+
}`}>
|
|
1482
|
+
{step.name}
|
|
1483
|
+
</h4>
|
|
1484
|
+
<p className="text-xs text-gray-400 mt-1 font-mono break-words leading-relaxed">
|
|
1485
|
+
{step.message}
|
|
1486
|
+
</p>
|
|
1487
|
+
</div>
|
|
1400
1488
|
</div>
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1489
|
+
);
|
|
1490
|
+
})}
|
|
1491
|
+
</div>
|
|
1492
|
+
|
|
1493
|
+
{creationError && (
|
|
1494
|
+
<div className="mt-6 p-4 bg-rose-500/10 border border-rose-500/20 text-rose-450 rounded-xl text-xs w-full max-w-md flex flex-col gap-3">
|
|
1495
|
+
<span className="font-bold flex items-center gap-1.5">
|
|
1496
|
+
<AlertCircle size={14} className="text-rose-450" /> Build Failed
|
|
1497
|
+
</span>
|
|
1498
|
+
<span className="font-mono">{creationError}</span>
|
|
1499
|
+
<button
|
|
1500
|
+
className="w-full mt-2 py-2 px-4 rounded-lg bg-rose-600 hover:bg-rose-700 text-white font-bold text-[11px] transition-colors cursor-pointer"
|
|
1501
|
+
onClick={() => {
|
|
1502
|
+
setCreating(false);
|
|
1503
|
+
setCreationError(null);
|
|
1504
|
+
}}
|
|
1505
|
+
>
|
|
1506
|
+
Dismiss
|
|
1507
|
+
</button>
|
|
1508
|
+
</div>
|
|
1509
|
+
)}
|
|
1411
1510
|
</div>
|
|
1412
|
-
|
|
1511
|
+
) : (
|
|
1512
|
+
<>
|
|
1513
|
+
<div className="mb-8">
|
|
1514
|
+
<label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Target AI Assistant(s)</label>
|
|
1515
|
+
<p className="text-xs text-gray-500 mb-4">
|
|
1516
|
+
We generate context configurations matching the specifications of each checked assistant.
|
|
1517
|
+
</p>
|
|
1518
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
1519
|
+
{aiAssistants.map((ai) => {
|
|
1520
|
+
const isSelected = selectedAI.includes(ai.name);
|
|
1521
|
+
return (
|
|
1522
|
+
<div
|
|
1523
|
+
key={ai.name}
|
|
1524
|
+
className={`bg-[#111827]/60 border rounded-xl p-4 flex flex-col gap-3 cursor-pointer hover:border-gray-700 transition-all ${
|
|
1525
|
+
isSelected ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
|
|
1526
|
+
}`}
|
|
1527
|
+
onClick={() => handleToggleAI(ai.name)}
|
|
1528
|
+
>
|
|
1529
|
+
<div className="flex justify-between items-center">
|
|
1530
|
+
<span className="text-sm font-bold text-white">{ai.displayName}</span>
|
|
1531
|
+
<span className={`text-[9px] px-2 py-0.5 rounded font-semibold uppercase ${
|
|
1532
|
+
ai.detected ? 'bg-emerald-500/10 text-emerald-400' : 'bg-gray-800 text-gray-500'
|
|
1533
|
+
}`}>
|
|
1534
|
+
{ai.detected ? 'Installed' : 'Missing'}
|
|
1535
|
+
</span>
|
|
1536
|
+
</div>
|
|
1537
|
+
<p className="text-[11px] text-gray-500">
|
|
1538
|
+
{ai.name === 'claude' && 'CLAUDE.md guidelines'}
|
|
1539
|
+
{ai.name === 'antigravity' && 'CLAUDE.md guidelines (harness)'}
|
|
1540
|
+
{ai.name === 'codex' && 'AGENTS.md config structure'}
|
|
1541
|
+
{ai.name === 'copilot' && 'GitHub Copilot Workspace configs'}
|
|
1542
|
+
{ai.name === 'cursor' && 'Cursor MDC rules and instructions'}
|
|
1543
|
+
</p>
|
|
1544
|
+
</div>
|
|
1545
|
+
);
|
|
1546
|
+
})}
|
|
1547
|
+
</div>
|
|
1548
|
+
</div>
|
|
1413
1549
|
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1550
|
+
<div className="mb-8">
|
|
1551
|
+
<label className="block text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">Open Workspace In</label>
|
|
1552
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
|
1553
|
+
{editors.map((ed) => {
|
|
1554
|
+
const isSelected = selectedEditor?.command === ed.command;
|
|
1555
|
+
return (
|
|
1556
|
+
<div
|
|
1557
|
+
key={ed.command}
|
|
1558
|
+
className={`bg-[#111827]/60 border rounded-xl p-4 flex flex-col cursor-pointer hover:border-gray-700 transition-all ${
|
|
1559
|
+
isSelected ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
|
|
1560
|
+
}`}
|
|
1561
|
+
onClick={() => setSelectedEditor(ed)}
|
|
1562
|
+
>
|
|
1563
|
+
<span className="text-sm font-bold text-white">{ed.name}</span>
|
|
1564
|
+
<span className={`text-[9px] mt-2 w-max px-2 py-0.5 rounded font-semibold uppercase ${
|
|
1565
|
+
ed.detected ? 'bg-emerald-500/10 text-emerald-400' : 'bg-gray-800 text-gray-500'
|
|
1566
|
+
}`}>
|
|
1567
|
+
{ed.detected ? 'Detected' : 'Missing'}
|
|
1568
|
+
</span>
|
|
1569
|
+
</div>
|
|
1570
|
+
);
|
|
1571
|
+
})}
|
|
1420
1572
|
<div
|
|
1421
|
-
key={ed.command}
|
|
1422
1573
|
className={`bg-[#111827]/60 border rounded-xl p-4 flex flex-col cursor-pointer hover:border-gray-700 transition-all ${
|
|
1423
|
-
|
|
1574
|
+
selectedEditor === null ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
|
|
1424
1575
|
}`}
|
|
1425
|
-
onClick={() => setSelectedEditor(
|
|
1576
|
+
onClick={() => setSelectedEditor(null)}
|
|
1426
1577
|
>
|
|
1427
|
-
<span className="text-sm font-bold text-white">
|
|
1428
|
-
<span className=
|
|
1429
|
-
|
|
1430
|
-
}`}>
|
|
1431
|
-
{ed.detected ? 'Detected' : 'Missing'}
|
|
1578
|
+
<span className="text-sm font-bold text-white">None</span>
|
|
1579
|
+
<span className="text-[9px] mt-2 w-max px-2 py-0.5 rounded font-semibold uppercase bg-gray-800 text-gray-500">
|
|
1580
|
+
Skip opening
|
|
1432
1581
|
</span>
|
|
1433
1582
|
</div>
|
|
1434
|
-
|
|
1435
|
-
})}
|
|
1436
|
-
<div
|
|
1437
|
-
className={`bg-[#111827]/60 border rounded-xl p-4 flex flex-col cursor-pointer hover:border-gray-700 transition-all ${
|
|
1438
|
-
selectedEditor === null ? 'border-indigo-500 bg-indigo-500/5' : 'border-gray-800/80'
|
|
1439
|
-
}`}
|
|
1440
|
-
onClick={() => setSelectedEditor(null)}
|
|
1441
|
-
>
|
|
1442
|
-
<span className="text-sm font-bold text-white">None</span>
|
|
1443
|
-
<span className="text-[9px] mt-2 w-max px-2 py-0.5 rounded font-semibold uppercase bg-gray-800 text-gray-500">
|
|
1444
|
-
Skip opening
|
|
1445
|
-
</span>
|
|
1583
|
+
</div>
|
|
1446
1584
|
</div>
|
|
1447
|
-
</div>
|
|
1448
|
-
</div>
|
|
1449
1585
|
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1586
|
+
<div className="mb-8 border border-gray-800/80 rounded-xl p-5 bg-gray-950/20">
|
|
1587
|
+
<h4 className="text-xs font-bold text-gray-400 uppercase tracking-wider mb-4 flex items-center gap-2">
|
|
1588
|
+
<Terminal size={14} className="text-indigo-400" /> Advanced Session Resumption Settings
|
|
1589
|
+
</h4>
|
|
1590
|
+
<p className="text-[11px] text-gray-500 mb-4">
|
|
1591
|
+
Configure setup and verification test commands. AI assistants and the dashboard use these to resume your sessions green.
|
|
1592
|
+
</p>
|
|
1593
|
+
<div className="space-y-4">
|
|
1594
|
+
<div>
|
|
1595
|
+
<label className="block text-[11px] font-semibold text-gray-400 mb-1.5">Verification / Test Command</label>
|
|
1596
|
+
<input
|
|
1597
|
+
type="text"
|
|
1598
|
+
className="w-full bg-[#030408] border border-gray-800 focus:border-indigo-500 rounded-lg px-3 py-2 text-xs font-mono text-white outline-none transition-all"
|
|
1599
|
+
placeholder="e.g., npm run test or vitest run"
|
|
1600
|
+
value={testCommand}
|
|
1601
|
+
onChange={(e) => setTestCommand(e.target.value)}
|
|
1602
|
+
/>
|
|
1603
|
+
</div>
|
|
1604
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
1605
|
+
<div>
|
|
1606
|
+
<label className="block text-[11px] font-semibold text-gray-400 mb-1.5">Mock / Database Command (Optional)</label>
|
|
1607
|
+
<input
|
|
1608
|
+
type="text"
|
|
1609
|
+
className="w-full bg-[#030408] border border-gray-800 focus:border-indigo-500 rounded-lg px-3 py-2 text-xs font-mono text-white outline-none transition-all"
|
|
1610
|
+
placeholder="e.g., docker compose up -d redis"
|
|
1611
|
+
value={mockCommand}
|
|
1612
|
+
onChange={(e) => setMockCommand(e.target.value)}
|
|
1613
|
+
/>
|
|
1614
|
+
</div>
|
|
1615
|
+
<div>
|
|
1616
|
+
<label className="block text-[11px] font-semibold text-gray-400 mb-1.5">Start / Run Command (Optional)</label>
|
|
1617
|
+
<input
|
|
1618
|
+
type="text"
|
|
1619
|
+
className="w-full bg-[#030408] border border-gray-800 focus:border-indigo-500 rounded-lg px-3 py-2 text-xs font-mono text-white outline-none transition-all"
|
|
1620
|
+
placeholder="e.g., npm run start:dev"
|
|
1621
|
+
value={startCommand}
|
|
1622
|
+
onChange={(e) => setStartCommand(e.target.value)}
|
|
1623
|
+
/>
|
|
1624
|
+
</div>
|
|
1625
|
+
</div>
|
|
1488
1626
|
</div>
|
|
1489
1627
|
</div>
|
|
1490
|
-
</div>
|
|
1491
|
-
</div>
|
|
1492
1628
|
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1629
|
+
<div className="flex justify-between">
|
|
1630
|
+
<button
|
|
1631
|
+
className="inline-flex items-center justify-center gap-2 px-5 py-3 rounded-lg text-sm font-semibold bg-gray-900 border border-gray-800 hover:bg-gray-800 hover:border-gray-700 text-white transition-all cursor-pointer"
|
|
1632
|
+
onClick={() => setActiveStep(1)}
|
|
1633
|
+
>
|
|
1634
|
+
<ArrowLeft size={16} /> Back
|
|
1635
|
+
</button>
|
|
1636
|
+
<button
|
|
1637
|
+
className="inline-flex items-center justify-center gap-2 px-6 py-3 rounded-lg text-sm font-semibold bg-gradient-to-r from-indigo-500 to-indigo-600 hover:from-indigo-600 hover:to-indigo-700 text-white shadow-lg shadow-indigo-500/20 transition-all cursor-pointer hover:-translate-y-0.5 active:translate-y-0 disabled:opacity-40 disabled:cursor-not-allowed"
|
|
1638
|
+
disabled={creating}
|
|
1639
|
+
onClick={handleCreateWorkspace}
|
|
1640
|
+
>
|
|
1641
|
+
{creating ? (
|
|
1642
|
+
<>
|
|
1643
|
+
<RefreshCw className="animate-spin" size={14} /> Building...
|
|
1644
|
+
</>
|
|
1645
|
+
) : (
|
|
1646
|
+
<>
|
|
1647
|
+
<Sparkles size={14} /> Build Workspace
|
|
1648
|
+
</>
|
|
1649
|
+
)}
|
|
1650
|
+
</button>
|
|
1651
|
+
</div>
|
|
1652
|
+
</>
|
|
1653
|
+
)}
|
|
1516
1654
|
</div>
|
|
1517
1655
|
)}
|
|
1518
1656
|
|
package/package.json
CHANGED
package/src/commands/create.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { confirm } from '@inquirer/prompts';
|
|
|
14
14
|
import { loadConfig } from '../core/config.js';
|
|
15
15
|
import { scanForRepos } from '../core/scanner.js';
|
|
16
16
|
import { createWorkspace } from '../core/workspace.js';
|
|
17
|
+
import { packWorkspace } from '../core/packer.js';
|
|
17
18
|
import { generateContextFiles } from '../generators/index.js';
|
|
18
19
|
import { analyzeAllRepos } from '../analyzers/index.js';
|
|
19
20
|
import { detectAIAssistants } from '../utils/detect-ai.js';
|
|
@@ -113,6 +114,18 @@ export async function createCommand(): Promise<void> {
|
|
|
113
114
|
console.log(chalk.cyan('\nGenerating AI context files...'));
|
|
114
115
|
await generateContextFiles(ctx, selectedAI, workspacePath);
|
|
115
116
|
|
|
117
|
+
// ── 8.5. Pack codebase context ──────────────────────────────────────
|
|
118
|
+
const packSpinner = ora('Packing codebase context with Repomix...').start();
|
|
119
|
+
try {
|
|
120
|
+
const packResult = await packWorkspace(workspacePath);
|
|
121
|
+
packSpinner.succeed(
|
|
122
|
+
`Packed codebase context (${packResult.totalFiles} files, ${(packResult.fileSize / 1024).toFixed(2)} KB)`
|
|
123
|
+
);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
packSpinner.fail('Failed to pack codebase context');
|
|
126
|
+
console.error(chalk.red(` ${error}`));
|
|
127
|
+
}
|
|
128
|
+
|
|
116
129
|
// ── 8. Open in editor ───────────────────────────────────────────────
|
|
117
130
|
const detectedEditors = await detectEditors();
|
|
118
131
|
const editor = await promptSelectEditor(detectedEditors);
|
package/src/commands/open.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { loadConfig } from '../core/config.js';
|
|
|
11
11
|
import { listWorkspaces } from '../core/workspace.js';
|
|
12
12
|
import { detectEditors } from '../utils/detect-editors.js';
|
|
13
13
|
import { promptSelectEditor } from '../utils/prompts.js';
|
|
14
|
+
import { findSessions } from '../utils/session-finder.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Lets the user pick an existing workspace and open it in an editor.
|
|
@@ -64,17 +65,48 @@ export async function openCommand(): Promise<void> {
|
|
|
64
65
|
if (confirmStart) {
|
|
65
66
|
console.log(chalk.cyan(`\n🚀 Starting ${assistant} session inside workspace...\n`));
|
|
66
67
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
const sessions = await findSessions(selected, loadedFeature.repos);
|
|
69
|
+
let cmdName = 'agy';
|
|
70
|
+
let cmdArgs: string[] = [];
|
|
71
|
+
|
|
72
|
+
if (assistant === 'claude') {
|
|
73
|
+
cmdName = 'claude';
|
|
74
|
+
} else if (assistant === 'codex') {
|
|
75
|
+
cmdName = 'codex';
|
|
76
|
+
} else if (assistant === 'copilot') {
|
|
77
|
+
cmdName = 'copilot';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (sessions.length > 0 && sessions[0].assistant === assistant) {
|
|
81
|
+
const latestSessionId = sessions[0].id;
|
|
82
|
+
if (assistant === 'antigravity') {
|
|
83
|
+
cmdArgs = ['--conversation', latestSessionId];
|
|
84
|
+
} else if (assistant === 'claude') {
|
|
85
|
+
cmdArgs = ['--resume', latestSessionId];
|
|
86
|
+
} else if (assistant === 'codex') {
|
|
87
|
+
cmdArgs = ['resume', latestSessionId];
|
|
88
|
+
} else if (assistant === 'copilot') {
|
|
89
|
+
cmdArgs = ['--resume', latestSessionId];
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
if (assistant === 'antigravity') {
|
|
93
|
+
cmdArgs = ['--continue'];
|
|
94
|
+
} else if (assistant === 'claude') {
|
|
95
|
+
cmdArgs = ['--resume'];
|
|
96
|
+
} else if (assistant === 'codex') {
|
|
97
|
+
cmdArgs = ['resume'];
|
|
98
|
+
} else if (assistant === 'copilot') {
|
|
99
|
+
cmdArgs = ['--resume'];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
71
102
|
|
|
72
103
|
try {
|
|
73
|
-
await execa(
|
|
104
|
+
await execa(cmdName, cmdArgs, { cwd: selected, stdio: 'inherit' });
|
|
74
105
|
console.log(chalk.green(`\n👋 Exited ${assistant} session.`));
|
|
75
106
|
} catch {
|
|
107
|
+
const fullCmd = [cmdName, ...cmdArgs].join(' ');
|
|
76
108
|
console.log(
|
|
77
|
-
chalk.yellow(`\n⚠️ Could not start ${assistant}. Please start it manually:\n ${chalk.dim(`cd "${selected}" && ${
|
|
109
|
+
chalk.yellow(`\n⚠️ Could not start ${assistant}. Please start it manually:\n ${chalk.dim(`cd "${selected}" && ${fullCmd}`)}`)
|
|
78
110
|
);
|
|
79
111
|
}
|
|
80
112
|
}
|