replicas-cli 0.2.28 → 0.2.29
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 +192 -338
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34,9 +34,9 @@ __export(index_exports, {
|
|
|
34
34
|
CLI_VERSION: () => CLI_VERSION
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(index_exports);
|
|
37
|
-
var
|
|
37
|
+
var import_config15 = require("dotenv/config");
|
|
38
38
|
var import_commander = require("commander");
|
|
39
|
-
var
|
|
39
|
+
var import_chalk17 = __toESM(require("chalk"));
|
|
40
40
|
|
|
41
41
|
// src/commands/login.ts
|
|
42
42
|
var import_http = __toESM(require("http"));
|
|
@@ -507,44 +507,14 @@ async function whoamiCommand() {
|
|
|
507
507
|
var import_chalk5 = __toESM(require("chalk"));
|
|
508
508
|
|
|
509
509
|
// src/lib/ssh.ts
|
|
510
|
-
var import_fs2 = __toESM(require("fs"));
|
|
511
|
-
var import_path2 = __toESM(require("path"));
|
|
512
510
|
var import_child_process = require("child_process");
|
|
513
|
-
var
|
|
514
|
-
function
|
|
515
|
-
if (!import_fs2.default.existsSync(SSH_KEYS_DIR)) {
|
|
516
|
-
import_fs2.default.mkdirSync(SSH_KEYS_DIR, { recursive: true, mode: 448 });
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
function getSSHKeyPath(sshKeyId) {
|
|
520
|
-
return import_path2.default.join(SSH_KEYS_DIR, `${sshKeyId}.pem`);
|
|
521
|
-
}
|
|
522
|
-
async function getSSHKey(sshKeyId) {
|
|
523
|
-
const keyPath = getSSHKeyPath(sshKeyId);
|
|
524
|
-
if (import_fs2.default.existsSync(keyPath)) {
|
|
525
|
-
return import_fs2.default.readFileSync(keyPath, "utf-8");
|
|
526
|
-
}
|
|
527
|
-
const response = await orgAuthenticatedFetch(
|
|
528
|
-
`/v1/keys/${sshKeyId}?includePrivateKey=true`
|
|
529
|
-
);
|
|
530
|
-
if (!response.privateKey) {
|
|
531
|
-
throw new Error("Failed to retrieve private key from server");
|
|
532
|
-
}
|
|
533
|
-
ensureSSHKeysDir();
|
|
534
|
-
import_fs2.default.writeFileSync(keyPath, response.privateKey, { mode: 384 });
|
|
535
|
-
return response.privateKey;
|
|
536
|
-
}
|
|
537
|
-
async function scpCopyFile(privateKeyPath, localPath, remotePath, remoteHost) {
|
|
511
|
+
var SSH_OPTIONS = ["-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null"];
|
|
512
|
+
async function scpCopyFile(token, host, localPath, remotePath) {
|
|
538
513
|
return new Promise((resolve, reject) => {
|
|
539
514
|
const scp = (0, import_child_process.spawn)("scp", [
|
|
540
|
-
|
|
541
|
-
privateKeyPath,
|
|
542
|
-
"-o",
|
|
543
|
-
"StrictHostKeyChecking=no",
|
|
544
|
-
"-o",
|
|
545
|
-
"UserKnownHostsFile=/dev/null",
|
|
515
|
+
...SSH_OPTIONS,
|
|
546
516
|
localPath,
|
|
547
|
-
|
|
517
|
+
`${token}@${host}:${remotePath}`
|
|
548
518
|
], {
|
|
549
519
|
stdio: "inherit"
|
|
550
520
|
});
|
|
@@ -558,24 +528,17 @@ async function scpCopyFile(privateKeyPath, localPath, remotePath, remoteHost) {
|
|
|
558
528
|
scp.on("error", reject);
|
|
559
529
|
});
|
|
560
530
|
}
|
|
561
|
-
async function connectSSH(
|
|
531
|
+
async function connectSSH(token, host, portMappings) {
|
|
562
532
|
return new Promise((resolve, reject) => {
|
|
563
|
-
const sshArgs = [
|
|
564
|
-
"-i",
|
|
565
|
-
privateKeyPath,
|
|
566
|
-
"-o",
|
|
567
|
-
"StrictHostKeyChecking=no",
|
|
568
|
-
"-o",
|
|
569
|
-
"UserKnownHostsFile=/dev/null"
|
|
570
|
-
];
|
|
533
|
+
const sshArgs = [...SSH_OPTIONS];
|
|
571
534
|
for (const [remotePort, localPort] of portMappings) {
|
|
572
535
|
sshArgs.push("-L", `${localPort}:localhost:${remotePort}`);
|
|
573
536
|
}
|
|
574
|
-
sshArgs.push(
|
|
537
|
+
sshArgs.push(`${token}@${host}`);
|
|
575
538
|
const ssh = (0, import_child_process.spawn)("ssh", sshArgs, {
|
|
576
539
|
stdio: "inherit"
|
|
577
540
|
});
|
|
578
|
-
ssh.on("close", (
|
|
541
|
+
ssh.on("close", () => {
|
|
579
542
|
resolve();
|
|
580
543
|
});
|
|
581
544
|
ssh.on("error", reject);
|
|
@@ -585,12 +548,10 @@ async function connectSSH(privateKeyPath, remoteHost, portMappings) {
|
|
|
585
548
|
// src/lib/workspace-connection.ts
|
|
586
549
|
var import_chalk4 = __toESM(require("chalk"));
|
|
587
550
|
var import_prompts = __toESM(require("prompts"));
|
|
588
|
-
var import_path5 = __toESM(require("path"));
|
|
589
|
-
var import_fs4 = __toESM(require("fs"));
|
|
590
551
|
|
|
591
552
|
// src/lib/git.ts
|
|
592
553
|
var import_child_process2 = require("child_process");
|
|
593
|
-
var
|
|
554
|
+
var import_path2 = __toESM(require("path"));
|
|
594
555
|
function getGitRoot() {
|
|
595
556
|
try {
|
|
596
557
|
const root = (0, import_child_process2.execSync)("git rev-parse --show-toplevel", {
|
|
@@ -604,7 +565,7 @@ function getGitRoot() {
|
|
|
604
565
|
}
|
|
605
566
|
function getGitRepoName() {
|
|
606
567
|
const root = getGitRoot();
|
|
607
|
-
return
|
|
568
|
+
return import_path2.default.basename(root);
|
|
608
569
|
}
|
|
609
570
|
function isInsideGitRepo() {
|
|
610
571
|
try {
|
|
@@ -619,16 +580,16 @@ function isInsideGitRepo() {
|
|
|
619
580
|
}
|
|
620
581
|
|
|
621
582
|
// src/lib/replicas-config.ts
|
|
622
|
-
var
|
|
623
|
-
var
|
|
583
|
+
var import_fs2 = __toESM(require("fs"));
|
|
584
|
+
var import_path3 = __toESM(require("path"));
|
|
624
585
|
function readReplicasConfig() {
|
|
625
586
|
try {
|
|
626
587
|
const gitRoot = getGitRoot();
|
|
627
|
-
const configPath =
|
|
628
|
-
if (!
|
|
588
|
+
const configPath = import_path3.default.join(gitRoot, "replicas.json");
|
|
589
|
+
if (!import_fs2.default.existsSync(configPath)) {
|
|
629
590
|
return null;
|
|
630
591
|
}
|
|
631
|
-
const data =
|
|
592
|
+
const data = import_fs2.default.readFileSync(configPath, "utf-8");
|
|
632
593
|
const config2 = JSON.parse(data);
|
|
633
594
|
if (config2.copy && !Array.isArray(config2.copy)) {
|
|
634
595
|
throw new Error('Invalid replicas.json: "copy" must be an array of file paths');
|
|
@@ -658,8 +619,8 @@ function validateCopyFiles(copyFiles) {
|
|
|
658
619
|
const valid = [];
|
|
659
620
|
const invalid = [];
|
|
660
621
|
for (const file of copyFiles) {
|
|
661
|
-
const fullPath =
|
|
662
|
-
if (
|
|
622
|
+
const fullPath = import_path3.default.join(gitRoot, file);
|
|
623
|
+
if (import_fs2.default.existsSync(fullPath)) {
|
|
663
624
|
valid.push(file);
|
|
664
625
|
} else {
|
|
665
626
|
invalid.push(file);
|
|
@@ -669,7 +630,7 @@ function validateCopyFiles(copyFiles) {
|
|
|
669
630
|
}
|
|
670
631
|
function getAbsoluteCopyPath(relativePath) {
|
|
671
632
|
const gitRoot = getGitRoot();
|
|
672
|
-
return
|
|
633
|
+
return import_path3.default.join(gitRoot, relativePath);
|
|
673
634
|
}
|
|
674
635
|
|
|
675
636
|
// src/lib/ports.ts
|
|
@@ -733,7 +694,7 @@ Found ${response.workspaces.length} workspaces matching "${workspaceName}":`));
|
|
|
733
694
|
choices: response.workspaces.map((ws) => ({
|
|
734
695
|
title: `${ws.name} (${ws.status || "unknown"})`,
|
|
735
696
|
value: ws.id,
|
|
736
|
-
description: `
|
|
697
|
+
description: `Status: ${ws.status || "unknown"}`
|
|
737
698
|
}))
|
|
738
699
|
});
|
|
739
700
|
if (!selectResponse.workspaceId) {
|
|
@@ -743,21 +704,18 @@ Found ${response.workspaces.length} workspaces matching "${workspaceName}":`));
|
|
|
743
704
|
}
|
|
744
705
|
console.log(import_chalk4.default.green(`
|
|
745
706
|
\u2713 Selected workspace: ${selectedWorkspace.name}`));
|
|
746
|
-
console.log(import_chalk4.default.gray(` IP: ${selectedWorkspace.ipv4_address}`));
|
|
747
707
|
console.log(import_chalk4.default.gray(` Status: ${selectedWorkspace.status || "unknown"}`));
|
|
748
708
|
if (selectedWorkspace.status === "sleeping") {
|
|
749
709
|
throw new Error(
|
|
750
710
|
"Workspace is currently sleeping. Please wake it up in the dashboard at https://replicas.dev before connecting."
|
|
751
711
|
);
|
|
752
712
|
}
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
import_fs4.default.writeFileSync(keyPath, privateKey, { mode: 384 });
|
|
760
|
-
console.log(import_chalk4.default.green("\u2713 SSH key ready"));
|
|
713
|
+
console.log(import_chalk4.default.blue("\nRequesting SSH access token..."));
|
|
714
|
+
const tokenResponse = await orgAuthenticatedFetch(
|
|
715
|
+
`/v1/workspaces/${selectedWorkspace.id}/ssh-token`,
|
|
716
|
+
{ method: "POST" }
|
|
717
|
+
);
|
|
718
|
+
console.log(import_chalk4.default.green("\u2713 SSH token received"));
|
|
761
719
|
let repoName = null;
|
|
762
720
|
if (options.copy) {
|
|
763
721
|
if (!isInsideGitRepo()) {
|
|
@@ -781,7 +739,7 @@ Warning: ${invalid.length} file(s) not found locally:`));
|
|
|
781
739
|
const remotePath = `/home/ubuntu/workspaces/${repoName}/${file}`;
|
|
782
740
|
console.log(import_chalk4.default.gray(` Copying ${file}...`));
|
|
783
741
|
try {
|
|
784
|
-
await scpCopyFile(
|
|
742
|
+
await scpCopyFile(tokenResponse.token, tokenResponse.host, localPath, remotePath);
|
|
785
743
|
console.log(import_chalk4.default.green(` \u2713 ${file}`));
|
|
786
744
|
} catch (error) {
|
|
787
745
|
console.log(import_chalk4.default.red(` \u2717 Failed to copy ${file}: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
@@ -813,7 +771,8 @@ Warning: ${invalid.length} file(s) not found locally:`));
|
|
|
813
771
|
console.log(import_chalk4.default.green("\u2713 Port forwarding configured"));
|
|
814
772
|
return {
|
|
815
773
|
workspace: selectedWorkspace,
|
|
816
|
-
|
|
774
|
+
sshToken: tokenResponse.token,
|
|
775
|
+
sshHost: tokenResponse.host,
|
|
817
776
|
portMappings,
|
|
818
777
|
repoName
|
|
819
778
|
};
|
|
@@ -826,17 +785,13 @@ async function connectCommand(workspaceName, options) {
|
|
|
826
785
|
process.exit(1);
|
|
827
786
|
}
|
|
828
787
|
try {
|
|
829
|
-
const { workspace,
|
|
788
|
+
const { workspace, sshToken, sshHost, portMappings } = await prepareWorkspaceConnection(
|
|
830
789
|
workspaceName,
|
|
831
790
|
options
|
|
832
791
|
);
|
|
833
792
|
console.log(import_chalk5.default.blue(`
|
|
834
793
|
Connecting to ${workspace.name}...`));
|
|
835
|
-
|
|
836
|
-
for (const [remotePort, localPort] of portMappings) {
|
|
837
|
-
sshCommand += ` -L ${localPort}:localhost:${remotePort}`;
|
|
838
|
-
}
|
|
839
|
-
sshCommand += ` ubuntu@${workspace.ipv4_address}`;
|
|
794
|
+
const sshCommand = `ssh ${sshToken}@${sshHost}`;
|
|
840
795
|
console.log(import_chalk5.default.gray(`SSH command: ${sshCommand}`));
|
|
841
796
|
if (portMappings.size > 0) {
|
|
842
797
|
console.log(import_chalk5.default.cyan("\nPort forwarding active:"));
|
|
@@ -845,7 +800,7 @@ Connecting to ${workspace.name}...`));
|
|
|
845
800
|
}
|
|
846
801
|
}
|
|
847
802
|
console.log(import_chalk5.default.gray("\nPress Ctrl+D to disconnect.\n"));
|
|
848
|
-
await connectSSH(
|
|
803
|
+
await connectSSH(sshToken, sshHost, portMappings);
|
|
849
804
|
console.log(import_chalk5.default.green("\n\u2713 Disconnected from workspace.\n"));
|
|
850
805
|
} catch (error) {
|
|
851
806
|
console.error(import_chalk5.default.red(`
|
|
@@ -859,28 +814,28 @@ var import_chalk6 = __toESM(require("chalk"));
|
|
|
859
814
|
var import_child_process4 = require("child_process");
|
|
860
815
|
|
|
861
816
|
// src/lib/ssh-config.ts
|
|
862
|
-
var
|
|
863
|
-
var
|
|
817
|
+
var import_fs3 = __toESM(require("fs"));
|
|
818
|
+
var import_path4 = __toESM(require("path"));
|
|
864
819
|
var import_os2 = __toESM(require("os"));
|
|
865
|
-
var SSH_CONFIG_PATH =
|
|
820
|
+
var SSH_CONFIG_PATH = import_path4.default.join(import_os2.default.homedir(), ".ssh", "config");
|
|
866
821
|
var REPLICAS_MARKER_START = "# === REPLICAS CLI MANAGED ENTRY START ===";
|
|
867
822
|
var REPLICAS_MARKER_END = "# === REPLICAS CLI MANAGED ENTRY END ===";
|
|
868
823
|
function ensureSSHDir() {
|
|
869
|
-
const sshDir =
|
|
870
|
-
if (!
|
|
871
|
-
|
|
824
|
+
const sshDir = import_path4.default.join(import_os2.default.homedir(), ".ssh");
|
|
825
|
+
if (!import_fs3.default.existsSync(sshDir)) {
|
|
826
|
+
import_fs3.default.mkdirSync(sshDir, { recursive: true, mode: 448 });
|
|
872
827
|
}
|
|
873
828
|
}
|
|
874
829
|
function readSSHConfig() {
|
|
875
830
|
ensureSSHDir();
|
|
876
|
-
if (!
|
|
831
|
+
if (!import_fs3.default.existsSync(SSH_CONFIG_PATH)) {
|
|
877
832
|
return "";
|
|
878
833
|
}
|
|
879
|
-
return
|
|
834
|
+
return import_fs3.default.readFileSync(SSH_CONFIG_PATH, "utf-8");
|
|
880
835
|
}
|
|
881
836
|
function writeSSHConfig(content) {
|
|
882
837
|
ensureSSHDir();
|
|
883
|
-
|
|
838
|
+
import_fs3.default.writeFileSync(SSH_CONFIG_PATH, content, { mode: 384 });
|
|
884
839
|
}
|
|
885
840
|
function generateConfigBlock(entry) {
|
|
886
841
|
const lines = [
|
|
@@ -888,7 +843,6 @@ function generateConfigBlock(entry) {
|
|
|
888
843
|
`Host ${entry.host}`,
|
|
889
844
|
` HostName ${entry.hostname}`,
|
|
890
845
|
` User ${entry.user}`,
|
|
891
|
-
` IdentityFile ${entry.identityFile}`,
|
|
892
846
|
` StrictHostKeyChecking no`,
|
|
893
847
|
` UserKnownHostsFile /dev/null`
|
|
894
848
|
];
|
|
@@ -949,7 +903,7 @@ async function codeCommand(workspaceName, options) {
|
|
|
949
903
|
process.exit(1);
|
|
950
904
|
}
|
|
951
905
|
try {
|
|
952
|
-
const { workspace,
|
|
906
|
+
const { workspace, sshToken, sshHost, portMappings, repoName } = await prepareWorkspaceConnection(
|
|
953
907
|
workspaceName,
|
|
954
908
|
options
|
|
955
909
|
);
|
|
@@ -957,9 +911,8 @@ async function codeCommand(workspaceName, options) {
|
|
|
957
911
|
console.log(import_chalk6.default.blue("\nConfiguring SSH connection..."));
|
|
958
912
|
addOrUpdateSSHConfigEntry({
|
|
959
913
|
host: hostAlias,
|
|
960
|
-
hostname:
|
|
961
|
-
user:
|
|
962
|
-
identityFile: sshKeyPath,
|
|
914
|
+
hostname: sshHost,
|
|
915
|
+
user: sshToken,
|
|
963
916
|
portForwards: portMappings
|
|
964
917
|
});
|
|
965
918
|
console.log(import_chalk6.default.green(`\u2713 SSH config entry created: ${hostAlias}`));
|
|
@@ -975,6 +928,8 @@ Opening ${ideCommand} for workspace ${workspace.name}...`));
|
|
|
975
928
|
console.log(import_chalk6.default.cyan(` \u2022 localhost:${localPort} \u2192 workspace:${remotePort}`));
|
|
976
929
|
}
|
|
977
930
|
}
|
|
931
|
+
console.log(import_chalk6.default.yellow(`
|
|
932
|
+
Note: SSH tokens expire after 3 hours. Run this command again to refresh.`));
|
|
978
933
|
const ide = (0, import_child_process4.spawn)(ideCommand, [
|
|
979
934
|
"--remote",
|
|
980
935
|
`ssh-remote+${hostAlias}`,
|
|
@@ -1595,75 +1550,10 @@ async function claudeAuthCommand(options = {}) {
|
|
|
1595
1550
|
}
|
|
1596
1551
|
}
|
|
1597
1552
|
|
|
1598
|
-
// src/commands/dev-sync.ts
|
|
1599
|
-
var import_chalk13 = __toESM(require("chalk"));
|
|
1600
|
-
var import_child_process5 = require("child_process");
|
|
1601
|
-
var import_path7 = __toESM(require("path"));
|
|
1602
|
-
async function devSyncCommand(workspaceName) {
|
|
1603
|
-
if (!isAuthenticated()) {
|
|
1604
|
-
console.log(import_chalk13.default.red('Not logged in. Please run "replicas login" first.'));
|
|
1605
|
-
process.exit(1);
|
|
1606
|
-
}
|
|
1607
|
-
try {
|
|
1608
|
-
const { workspace, sshKeyPath } = await prepareWorkspaceConnection(workspaceName, {});
|
|
1609
|
-
if (!workspace.ipv4_address) {
|
|
1610
|
-
throw new Error("Workspace does not have an IP address");
|
|
1611
|
-
}
|
|
1612
|
-
console.log(import_chalk13.default.blue(`
|
|
1613
|
-
Syncing engine to ${workspace.name}...`));
|
|
1614
|
-
const scriptPath = import_path7.default.resolve(__dirname, "../../../engine/scripts/dev-sync.sh");
|
|
1615
|
-
const devSync = (0, import_child_process5.spawn)(scriptPath, [
|
|
1616
|
-
"--ip",
|
|
1617
|
-
workspace.ipv4_address,
|
|
1618
|
-
"--key",
|
|
1619
|
-
sshKeyPath
|
|
1620
|
-
], {
|
|
1621
|
-
stdio: "inherit",
|
|
1622
|
-
shell: true
|
|
1623
|
-
});
|
|
1624
|
-
await new Promise((resolve, reject) => {
|
|
1625
|
-
devSync.on("close", (code) => {
|
|
1626
|
-
if (code === 0) {
|
|
1627
|
-
resolve();
|
|
1628
|
-
} else {
|
|
1629
|
-
reject(new Error(`dev-sync script exited with code ${code}`));
|
|
1630
|
-
}
|
|
1631
|
-
});
|
|
1632
|
-
devSync.on("error", (error) => {
|
|
1633
|
-
reject(error);
|
|
1634
|
-
});
|
|
1635
|
-
});
|
|
1636
|
-
console.log(import_chalk13.default.green("\n\u2713 Engine synced successfully.\n"));
|
|
1637
|
-
console.log(import_chalk13.default.blue("Viewing logs (Ctrl+C to exit)...\n"));
|
|
1638
|
-
const logs = (0, import_child_process5.spawn)("ssh", [
|
|
1639
|
-
"-i",
|
|
1640
|
-
sshKeyPath,
|
|
1641
|
-
`ubuntu@${workspace.ipv4_address}`,
|
|
1642
|
-
"sudo journalctl -fu replicas-engine"
|
|
1643
|
-
], {
|
|
1644
|
-
stdio: "inherit"
|
|
1645
|
-
});
|
|
1646
|
-
process.on("SIGINT", () => {
|
|
1647
|
-
logs.kill("SIGTERM");
|
|
1648
|
-
console.log(import_chalk13.default.green("\n\n\u2713 Disconnected from logs.\n"));
|
|
1649
|
-
process.exit(0);
|
|
1650
|
-
});
|
|
1651
|
-
await new Promise((resolve) => {
|
|
1652
|
-
logs.on("close", () => {
|
|
1653
|
-
resolve();
|
|
1654
|
-
});
|
|
1655
|
-
});
|
|
1656
|
-
} catch (error) {
|
|
1657
|
-
console.error(import_chalk13.default.red(`
|
|
1658
|
-
Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
1659
|
-
process.exit(1);
|
|
1660
|
-
}
|
|
1661
|
-
}
|
|
1662
|
-
|
|
1663
1553
|
// src/commands/init.ts
|
|
1664
|
-
var
|
|
1665
|
-
var
|
|
1666
|
-
var
|
|
1554
|
+
var import_chalk13 = __toESM(require("chalk"));
|
|
1555
|
+
var import_fs4 = __toESM(require("fs"));
|
|
1556
|
+
var import_path5 = __toESM(require("path"));
|
|
1667
1557
|
var REPLICAS_CONFIG_FILENAME = "replicas.json";
|
|
1668
1558
|
function getDefaultConfig() {
|
|
1669
1559
|
return {
|
|
@@ -1677,34 +1567,34 @@ function getDefaultConfig() {
|
|
|
1677
1567
|
};
|
|
1678
1568
|
}
|
|
1679
1569
|
function initCommand(options) {
|
|
1680
|
-
const configPath =
|
|
1681
|
-
if (
|
|
1570
|
+
const configPath = import_path5.default.join(process.cwd(), REPLICAS_CONFIG_FILENAME);
|
|
1571
|
+
if (import_fs4.default.existsSync(configPath) && !options.force) {
|
|
1682
1572
|
console.log(
|
|
1683
|
-
|
|
1573
|
+
import_chalk13.default.yellow(
|
|
1684
1574
|
`${REPLICAS_CONFIG_FILENAME} already exists in this directory.`
|
|
1685
1575
|
)
|
|
1686
1576
|
);
|
|
1687
|
-
console.log(
|
|
1577
|
+
console.log(import_chalk13.default.gray("Use --force to overwrite the existing file."));
|
|
1688
1578
|
return;
|
|
1689
1579
|
}
|
|
1690
1580
|
const defaultConfig = getDefaultConfig();
|
|
1691
1581
|
const configContent = JSON.stringify(defaultConfig, null, 2);
|
|
1692
1582
|
try {
|
|
1693
|
-
|
|
1694
|
-
console.log(
|
|
1583
|
+
import_fs4.default.writeFileSync(configPath, configContent + "\n", "utf-8");
|
|
1584
|
+
console.log(import_chalk13.default.green(`\u2713 Created ${REPLICAS_CONFIG_FILENAME}`));
|
|
1695
1585
|
console.log("");
|
|
1696
|
-
console.log(
|
|
1586
|
+
console.log(import_chalk13.default.gray("Configuration options:"));
|
|
1697
1587
|
console.log(
|
|
1698
|
-
|
|
1588
|
+
import_chalk13.default.gray(' copy - Files to sync to the workspace (e.g., [".env"])')
|
|
1699
1589
|
);
|
|
1700
1590
|
console.log(
|
|
1701
|
-
|
|
1591
|
+
import_chalk13.default.gray(" ports - Ports to forward from the workspace (e.g., [3000, 8080])")
|
|
1702
1592
|
);
|
|
1703
1593
|
console.log(
|
|
1704
|
-
|
|
1594
|
+
import_chalk13.default.gray(" systemPrompt - Custom instructions for AI coding assistants")
|
|
1705
1595
|
);
|
|
1706
1596
|
console.log(
|
|
1707
|
-
|
|
1597
|
+
import_chalk13.default.gray(" startHook - Commands to run on workspace startup")
|
|
1708
1598
|
);
|
|
1709
1599
|
} catch (error) {
|
|
1710
1600
|
throw new Error(
|
|
@@ -1714,7 +1604,7 @@ function initCommand(options) {
|
|
|
1714
1604
|
}
|
|
1715
1605
|
|
|
1716
1606
|
// src/lib/version-check.ts
|
|
1717
|
-
var
|
|
1607
|
+
var import_chalk14 = __toESM(require("chalk"));
|
|
1718
1608
|
var MONOLITH_URL2 = process.env.REPLICAS_MONOLITH_URL || "https://api.replicas.dev";
|
|
1719
1609
|
var VERSION_CHECK_TIMEOUT = 2e3;
|
|
1720
1610
|
function compareVersions(v1, v2) {
|
|
@@ -1740,9 +1630,9 @@ async function checkForUpdates(currentVersion) {
|
|
|
1740
1630
|
const data = await response.json();
|
|
1741
1631
|
const latestVersion = data.version;
|
|
1742
1632
|
if (compareVersions(latestVersion, currentVersion) > 0) {
|
|
1743
|
-
console.error(
|
|
1633
|
+
console.error(import_chalk14.default.gray(`
|
|
1744
1634
|
Update available: ${currentVersion} \u2192 ${latestVersion}`));
|
|
1745
|
-
console.error(
|
|
1635
|
+
console.error(import_chalk14.default.gray(`Run: npm i -g replicas-cli@latest
|
|
1746
1636
|
`));
|
|
1747
1637
|
}
|
|
1748
1638
|
} catch {
|
|
@@ -1750,9 +1640,17 @@ Update available: ${currentVersion} \u2192 ${latestVersion}`));
|
|
|
1750
1640
|
}
|
|
1751
1641
|
|
|
1752
1642
|
// src/commands/replica.ts
|
|
1753
|
-
var
|
|
1643
|
+
var import_chalk15 = __toESM(require("chalk"));
|
|
1754
1644
|
var import_prompts3 = __toESM(require("prompts"));
|
|
1755
1645
|
|
|
1646
|
+
// ../shared/src/sandbox.ts
|
|
1647
|
+
var SANDBOX_LIFECYCLE = {
|
|
1648
|
+
AUTO_STOP_MINUTES: 60,
|
|
1649
|
+
AUTO_ARCHIVE_MINUTES: 60 * 24 * 7,
|
|
1650
|
+
AUTO_DELETE_MINUTES: -1,
|
|
1651
|
+
SSH_TOKEN_EXPIRATION_MINUTES: 3 * 60
|
|
1652
|
+
};
|
|
1653
|
+
|
|
1756
1654
|
// ../shared/src/display-message/parsers/codex-parser.ts
|
|
1757
1655
|
function safeJsonParse(str, fallback) {
|
|
1758
1656
|
try {
|
|
@@ -2181,12 +2079,9 @@ function formatDate(dateString) {
|
|
|
2181
2079
|
function formatStatus(status) {
|
|
2182
2080
|
switch (status) {
|
|
2183
2081
|
case "active":
|
|
2184
|
-
return
|
|
2185
|
-
case "booting":
|
|
2186
|
-
case "initializing":
|
|
2187
|
-
return import_chalk16.default.yellow(status);
|
|
2082
|
+
return import_chalk15.default.green(status);
|
|
2188
2083
|
case "sleeping":
|
|
2189
|
-
return
|
|
2084
|
+
return import_chalk15.default.gray(status);
|
|
2190
2085
|
default:
|
|
2191
2086
|
return status;
|
|
2192
2087
|
}
|
|
@@ -2199,87 +2094,87 @@ function formatDisplayMessage(message) {
|
|
|
2199
2094
|
const time = new Date(message.timestamp).toLocaleTimeString();
|
|
2200
2095
|
switch (message.type) {
|
|
2201
2096
|
case "user":
|
|
2202
|
-
console.log(
|
|
2097
|
+
console.log(import_chalk15.default.blue(`
|
|
2203
2098
|
[${time}] USER:`));
|
|
2204
|
-
console.log(
|
|
2099
|
+
console.log(import_chalk15.default.white(` ${truncate(message.content, 500)}`));
|
|
2205
2100
|
break;
|
|
2206
2101
|
case "agent":
|
|
2207
|
-
console.log(
|
|
2102
|
+
console.log(import_chalk15.default.green(`
|
|
2208
2103
|
[${time}] ASSISTANT:`));
|
|
2209
|
-
console.log(
|
|
2104
|
+
console.log(import_chalk15.default.white(` ${truncate(message.content, 500)}`));
|
|
2210
2105
|
break;
|
|
2211
2106
|
case "reasoning":
|
|
2212
|
-
console.log(
|
|
2107
|
+
console.log(import_chalk15.default.gray(`
|
|
2213
2108
|
[${time}] THINKING:`));
|
|
2214
|
-
console.log(
|
|
2109
|
+
console.log(import_chalk15.default.gray(` ${truncate(message.content, 300)}`));
|
|
2215
2110
|
break;
|
|
2216
2111
|
case "command":
|
|
2217
|
-
console.log(
|
|
2112
|
+
console.log(import_chalk15.default.magenta(`
|
|
2218
2113
|
[${time}] COMMAND:`));
|
|
2219
|
-
console.log(
|
|
2114
|
+
console.log(import_chalk15.default.white(` $ ${message.command}`));
|
|
2220
2115
|
if (message.output) {
|
|
2221
|
-
console.log(
|
|
2116
|
+
console.log(import_chalk15.default.gray(` ${truncate(message.output, 200)}`));
|
|
2222
2117
|
}
|
|
2223
2118
|
if (message.exitCode !== void 0) {
|
|
2224
|
-
const exitColor = message.exitCode === 0 ?
|
|
2119
|
+
const exitColor = message.exitCode === 0 ? import_chalk15.default.green : import_chalk15.default.red;
|
|
2225
2120
|
console.log(exitColor(` Exit code: ${message.exitCode}`));
|
|
2226
2121
|
}
|
|
2227
2122
|
break;
|
|
2228
2123
|
case "file_change":
|
|
2229
|
-
console.log(
|
|
2124
|
+
console.log(import_chalk15.default.yellow(`
|
|
2230
2125
|
[${time}] FILE CHANGES:`));
|
|
2231
2126
|
for (const change of message.changes) {
|
|
2232
2127
|
const icon = change.kind === "add" ? "+" : change.kind === "delete" ? "-" : "~";
|
|
2233
|
-
const color = change.kind === "add" ?
|
|
2128
|
+
const color = change.kind === "add" ? import_chalk15.default.green : change.kind === "delete" ? import_chalk15.default.red : import_chalk15.default.yellow;
|
|
2234
2129
|
console.log(color(` ${icon} ${change.path}`));
|
|
2235
2130
|
}
|
|
2236
2131
|
break;
|
|
2237
2132
|
case "patch":
|
|
2238
|
-
console.log(
|
|
2133
|
+
console.log(import_chalk15.default.yellow(`
|
|
2239
2134
|
[${time}] PATCH:`));
|
|
2240
2135
|
for (const op of message.operations) {
|
|
2241
2136
|
const icon = op.action === "add" ? "+" : op.action === "delete" ? "-" : "~";
|
|
2242
|
-
const color = op.action === "add" ?
|
|
2137
|
+
const color = op.action === "add" ? import_chalk15.default.green : op.action === "delete" ? import_chalk15.default.red : import_chalk15.default.yellow;
|
|
2243
2138
|
console.log(color(` ${icon} ${op.path}`));
|
|
2244
2139
|
}
|
|
2245
2140
|
break;
|
|
2246
2141
|
case "tool_call":
|
|
2247
|
-
console.log(
|
|
2142
|
+
console.log(import_chalk15.default.cyan(`
|
|
2248
2143
|
[${time}] TOOL: ${message.tool}`));
|
|
2249
2144
|
if (message.output) {
|
|
2250
|
-
console.log(
|
|
2145
|
+
console.log(import_chalk15.default.gray(` ${truncate(message.output, 200)}`));
|
|
2251
2146
|
}
|
|
2252
2147
|
break;
|
|
2253
2148
|
case "web_search":
|
|
2254
|
-
console.log(
|
|
2149
|
+
console.log(import_chalk15.default.cyan(`
|
|
2255
2150
|
[${time}] WEB SEARCH:`));
|
|
2256
|
-
console.log(
|
|
2151
|
+
console.log(import_chalk15.default.white(` "${message.query}"`));
|
|
2257
2152
|
break;
|
|
2258
2153
|
case "todo_list":
|
|
2259
|
-
console.log(
|
|
2154
|
+
console.log(import_chalk15.default.blue(`
|
|
2260
2155
|
[${time}] PLAN:`));
|
|
2261
2156
|
for (const item of message.items) {
|
|
2262
|
-
const icon = item.completed ?
|
|
2157
|
+
const icon = item.completed ? import_chalk15.default.green("[x]") : import_chalk15.default.gray("[ ]");
|
|
2263
2158
|
console.log(` ${icon} ${item.text}`);
|
|
2264
2159
|
}
|
|
2265
2160
|
break;
|
|
2266
2161
|
case "subagent":
|
|
2267
|
-
console.log(
|
|
2162
|
+
console.log(import_chalk15.default.magenta(`
|
|
2268
2163
|
[${time}] SUBAGENT: ${message.description}`));
|
|
2269
2164
|
if (message.output) {
|
|
2270
|
-
console.log(
|
|
2165
|
+
console.log(import_chalk15.default.gray(` ${truncate(message.output, 200)}`));
|
|
2271
2166
|
}
|
|
2272
2167
|
break;
|
|
2273
2168
|
case "error":
|
|
2274
|
-
console.log(
|
|
2169
|
+
console.log(import_chalk15.default.red(`
|
|
2275
2170
|
[${time}] ERROR:`));
|
|
2276
|
-
console.log(
|
|
2171
|
+
console.log(import_chalk15.default.red(` ${message.message}`));
|
|
2277
2172
|
break;
|
|
2278
2173
|
}
|
|
2279
2174
|
}
|
|
2280
2175
|
async function replicaListCommand(options) {
|
|
2281
2176
|
if (!isAuthenticated()) {
|
|
2282
|
-
console.log(
|
|
2177
|
+
console.log(import_chalk15.default.red('Not logged in. Please run "replicas login" first.'));
|
|
2283
2178
|
process.exit(1);
|
|
2284
2179
|
}
|
|
2285
2180
|
try {
|
|
@@ -2291,96 +2186,93 @@ async function replicaListCommand(options) {
|
|
|
2291
2186
|
`/v1/replica${query ? "?" + query : ""}`
|
|
2292
2187
|
);
|
|
2293
2188
|
if (response.replicas.length === 0) {
|
|
2294
|
-
console.log(
|
|
2189
|
+
console.log(import_chalk15.default.yellow("\nNo replicas found.\n"));
|
|
2295
2190
|
return;
|
|
2296
2191
|
}
|
|
2297
|
-
console.log(
|
|
2192
|
+
console.log(import_chalk15.default.green(`
|
|
2298
2193
|
Replicas (Page ${response.page} of ${response.totalPages}, Total: ${response.total}):
|
|
2299
2194
|
`));
|
|
2300
2195
|
for (const replica of response.replicas) {
|
|
2301
|
-
console.log(
|
|
2302
|
-
console.log(
|
|
2196
|
+
console.log(import_chalk15.default.white(` ${replica.name}`));
|
|
2197
|
+
console.log(import_chalk15.default.gray(` ID: ${replica.id}`));
|
|
2303
2198
|
if (replica.repository) {
|
|
2304
|
-
console.log(
|
|
2199
|
+
console.log(import_chalk15.default.gray(` Repository: ${replica.repository}`));
|
|
2305
2200
|
}
|
|
2306
|
-
console.log(
|
|
2307
|
-
console.log(
|
|
2308
|
-
console.log(import_chalk16.default.gray(` Created: ${formatDate(replica.created_at)}`));
|
|
2201
|
+
console.log(import_chalk15.default.gray(` Status: ${formatStatus(replica.status)}`));
|
|
2202
|
+
console.log(import_chalk15.default.gray(` Created: ${formatDate(replica.created_at)}`));
|
|
2309
2203
|
if (replica.pull_requests && replica.pull_requests.length > 0) {
|
|
2310
|
-
console.log(
|
|
2204
|
+
console.log(import_chalk15.default.gray(` Pull Requests:`));
|
|
2311
2205
|
for (const pr of replica.pull_requests) {
|
|
2312
|
-
console.log(
|
|
2206
|
+
console.log(import_chalk15.default.cyan(` - #${pr.number}: ${pr.url}`));
|
|
2313
2207
|
}
|
|
2314
2208
|
}
|
|
2315
2209
|
console.log();
|
|
2316
2210
|
}
|
|
2317
2211
|
} catch (error) {
|
|
2318
|
-
console.error(
|
|
2212
|
+
console.error(import_chalk15.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2319
2213
|
process.exit(1);
|
|
2320
2214
|
}
|
|
2321
2215
|
}
|
|
2322
2216
|
async function replicaGetCommand(id) {
|
|
2323
2217
|
if (!isAuthenticated()) {
|
|
2324
|
-
console.log(
|
|
2218
|
+
console.log(import_chalk15.default.red('Not logged in. Please run "replicas login" first.'));
|
|
2325
2219
|
process.exit(1);
|
|
2326
2220
|
}
|
|
2327
2221
|
try {
|
|
2328
2222
|
const response = await orgAuthenticatedFetch(`/v1/replica/${id}`);
|
|
2329
2223
|
const replica = response.replica;
|
|
2330
|
-
console.log(
|
|
2224
|
+
console.log(import_chalk15.default.green(`
|
|
2331
2225
|
Replica: ${replica.name}
|
|
2332
2226
|
`));
|
|
2333
|
-
console.log(
|
|
2227
|
+
console.log(import_chalk15.default.gray(` ID: ${replica.id}`));
|
|
2334
2228
|
if (replica.repository) {
|
|
2335
|
-
console.log(
|
|
2229
|
+
console.log(import_chalk15.default.gray(` Repository: ${replica.repository}`));
|
|
2336
2230
|
}
|
|
2337
|
-
console.log(
|
|
2338
|
-
console.log(
|
|
2339
|
-
console.log(import_chalk16.default.gray(` Created: ${formatDate(replica.created_at)}`));
|
|
2231
|
+
console.log(import_chalk15.default.gray(` Status: ${formatStatus(replica.status)}`));
|
|
2232
|
+
console.log(import_chalk15.default.gray(` Created: ${formatDate(replica.created_at)}`));
|
|
2340
2233
|
if (replica.waking) {
|
|
2341
|
-
console.log(
|
|
2234
|
+
console.log(import_chalk15.default.yellow("\n Workspace is waking from sleep. Retry in 30-90 seconds for full details.\n"));
|
|
2342
2235
|
} else {
|
|
2343
2236
|
if (replica.coding_agent) {
|
|
2344
|
-
console.log(
|
|
2237
|
+
console.log(import_chalk15.default.gray(` Coding Agent: ${replica.coding_agent}`));
|
|
2345
2238
|
}
|
|
2346
2239
|
if (replica.branch) {
|
|
2347
|
-
console.log(
|
|
2240
|
+
console.log(import_chalk15.default.gray(` Branch: ${replica.branch}`));
|
|
2348
2241
|
}
|
|
2349
2242
|
if (replica.git_diff) {
|
|
2350
|
-
console.log(
|
|
2243
|
+
console.log(import_chalk15.default.gray(` Changes: ${import_chalk15.default.green(`+${replica.git_diff.added}`)} / ${import_chalk15.default.red(`-${replica.git_diff.removed}`)}`));
|
|
2351
2244
|
}
|
|
2352
2245
|
}
|
|
2353
2246
|
if (replica.pull_requests && replica.pull_requests.length > 0) {
|
|
2354
|
-
console.log(
|
|
2247
|
+
console.log(import_chalk15.default.gray(` Pull Requests:`));
|
|
2355
2248
|
for (const pr of replica.pull_requests) {
|
|
2356
|
-
console.log(
|
|
2249
|
+
console.log(import_chalk15.default.cyan(` - #${pr.number}: ${pr.url}`));
|
|
2357
2250
|
}
|
|
2358
2251
|
}
|
|
2359
2252
|
console.log();
|
|
2360
2253
|
} catch (error) {
|
|
2361
|
-
console.error(
|
|
2254
|
+
console.error(import_chalk15.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2362
2255
|
process.exit(1);
|
|
2363
2256
|
}
|
|
2364
2257
|
}
|
|
2365
2258
|
async function replicaCreateCommand(name, options) {
|
|
2366
2259
|
if (!isAuthenticated()) {
|
|
2367
|
-
console.log(
|
|
2260
|
+
console.log(import_chalk15.default.red('Not logged in. Please run "replicas login" first.'));
|
|
2368
2261
|
process.exit(1);
|
|
2369
2262
|
}
|
|
2370
2263
|
try {
|
|
2371
2264
|
const repoResponse = await orgAuthenticatedFetch("/v1/repositories");
|
|
2372
2265
|
const repositories = repoResponse.repositories;
|
|
2373
2266
|
if (repositories.length === 0) {
|
|
2374
|
-
console.log(
|
|
2267
|
+
console.log(import_chalk15.default.red("No repositories found. Please add a repository first."));
|
|
2375
2268
|
process.exit(1);
|
|
2376
2269
|
}
|
|
2377
2270
|
let replicaName = name;
|
|
2378
2271
|
let message = options.message;
|
|
2379
2272
|
let repository = options.repository;
|
|
2380
|
-
let instanceType = options.instanceType;
|
|
2381
2273
|
let codingAgent = options.agent;
|
|
2382
2274
|
if (replicaName && /\s/.test(replicaName)) {
|
|
2383
|
-
console.log(
|
|
2275
|
+
console.log(import_chalk15.default.red("Replica name cannot contain spaces."));
|
|
2384
2276
|
process.exit(1);
|
|
2385
2277
|
}
|
|
2386
2278
|
if (!replicaName) {
|
|
@@ -2395,7 +2287,7 @@ async function replicaCreateCommand(name, options) {
|
|
|
2395
2287
|
}
|
|
2396
2288
|
});
|
|
2397
2289
|
if (!response2.name) {
|
|
2398
|
-
console.log(
|
|
2290
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2399
2291
|
return;
|
|
2400
2292
|
}
|
|
2401
2293
|
replicaName = response2.name;
|
|
@@ -2412,7 +2304,7 @@ async function replicaCreateCommand(name, options) {
|
|
|
2412
2304
|
}))
|
|
2413
2305
|
});
|
|
2414
2306
|
if (!response2.repository) {
|
|
2415
|
-
console.log(
|
|
2307
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2416
2308
|
return;
|
|
2417
2309
|
}
|
|
2418
2310
|
repository = response2.repository;
|
|
@@ -2425,29 +2317,11 @@ async function replicaCreateCommand(name, options) {
|
|
|
2425
2317
|
validate: (value) => value.trim() ? true : "Message is required"
|
|
2426
2318
|
});
|
|
2427
2319
|
if (!response2.message) {
|
|
2428
|
-
console.log(
|
|
2320
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2429
2321
|
return;
|
|
2430
2322
|
}
|
|
2431
2323
|
message = response2.message;
|
|
2432
2324
|
}
|
|
2433
|
-
if (!instanceType) {
|
|
2434
|
-
const response2 = await (0, import_prompts3.default)({
|
|
2435
|
-
type: "select",
|
|
2436
|
-
name: "instanceType",
|
|
2437
|
-
message: "Select instance type:",
|
|
2438
|
-
choices: [
|
|
2439
|
-
{ title: "Standard (2 vCPU, 4GB RAM)", value: "standard" },
|
|
2440
|
-
{ title: "Large (2 vCPU, 8GB RAM)", value: "large" },
|
|
2441
|
-
{ title: "Power (4 vCPU, 16GB RAM)", value: "power" }
|
|
2442
|
-
],
|
|
2443
|
-
initial: 0
|
|
2444
|
-
});
|
|
2445
|
-
if (!response2.instanceType) {
|
|
2446
|
-
console.log(import_chalk16.default.yellow("\nCancelled."));
|
|
2447
|
-
return;
|
|
2448
|
-
}
|
|
2449
|
-
instanceType = response2.instanceType;
|
|
2450
|
-
}
|
|
2451
2325
|
if (!codingAgent) {
|
|
2452
2326
|
const response2 = await (0, import_prompts3.default)({
|
|
2453
2327
|
type: "select",
|
|
@@ -2460,46 +2334,40 @@ async function replicaCreateCommand(name, options) {
|
|
|
2460
2334
|
initial: 0
|
|
2461
2335
|
});
|
|
2462
2336
|
if (!response2.agent) {
|
|
2463
|
-
console.log(
|
|
2337
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2464
2338
|
return;
|
|
2465
2339
|
}
|
|
2466
2340
|
codingAgent = response2.agent;
|
|
2467
2341
|
}
|
|
2468
|
-
if (!instanceType || !["standard", "large", "power"].includes(instanceType)) {
|
|
2469
|
-
console.log(import_chalk16.default.red(`Invalid instance type: ${instanceType}. Must be one of: standard, large, power`));
|
|
2470
|
-
process.exit(1);
|
|
2471
|
-
}
|
|
2472
2342
|
if (!codingAgent || !["claude", "codex"].includes(codingAgent)) {
|
|
2473
|
-
console.log(
|
|
2343
|
+
console.log(import_chalk15.default.red(`Invalid coding agent: ${codingAgent}. Must be one of: claude, codex`));
|
|
2474
2344
|
process.exit(1);
|
|
2475
2345
|
}
|
|
2476
2346
|
const body = {
|
|
2477
2347
|
name: replicaName,
|
|
2478
2348
|
message,
|
|
2479
2349
|
repository,
|
|
2480
|
-
instance_type: instanceType,
|
|
2481
2350
|
coding_agent: codingAgent
|
|
2482
2351
|
};
|
|
2483
|
-
console.log(
|
|
2352
|
+
console.log(import_chalk15.default.gray("\nCreating replica..."));
|
|
2484
2353
|
const response = await orgAuthenticatedFetch("/v1/replica", {
|
|
2485
2354
|
method: "POST",
|
|
2486
2355
|
body
|
|
2487
2356
|
});
|
|
2488
2357
|
const replica = response.replica;
|
|
2489
|
-
console.log(
|
|
2358
|
+
console.log(import_chalk15.default.green(`
|
|
2490
2359
|
Created replica: ${replica.name}`));
|
|
2491
|
-
console.log(
|
|
2492
|
-
console.log(
|
|
2493
|
-
console.log(import_chalk16.default.gray(` Status: ${formatStatus(replica.status)}`));
|
|
2360
|
+
console.log(import_chalk15.default.gray(` ID: ${replica.id}`));
|
|
2361
|
+
console.log(import_chalk15.default.gray(` Status: ${formatStatus(replica.status)}`));
|
|
2494
2362
|
console.log();
|
|
2495
2363
|
} catch (error) {
|
|
2496
|
-
console.error(
|
|
2364
|
+
console.error(import_chalk15.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2497
2365
|
process.exit(1);
|
|
2498
2366
|
}
|
|
2499
2367
|
}
|
|
2500
2368
|
async function replicaSendCommand(id, options) {
|
|
2501
2369
|
if (!isAuthenticated()) {
|
|
2502
|
-
console.log(
|
|
2370
|
+
console.log(import_chalk15.default.red('Not logged in. Please run "replicas login" first.'));
|
|
2503
2371
|
process.exit(1);
|
|
2504
2372
|
}
|
|
2505
2373
|
try {
|
|
@@ -2512,7 +2380,7 @@ async function replicaSendCommand(id, options) {
|
|
|
2512
2380
|
validate: (value) => value.trim() ? true : "Message is required"
|
|
2513
2381
|
});
|
|
2514
2382
|
if (!response2.message) {
|
|
2515
|
-
console.log(
|
|
2383
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2516
2384
|
return;
|
|
2517
2385
|
}
|
|
2518
2386
|
message = response2.message;
|
|
@@ -2522,7 +2390,7 @@ async function replicaSendCommand(id, options) {
|
|
|
2522
2390
|
};
|
|
2523
2391
|
if (options.agent) {
|
|
2524
2392
|
if (!["claude", "codex"].includes(options.agent)) {
|
|
2525
|
-
console.log(
|
|
2393
|
+
console.log(import_chalk15.default.red(`Invalid coding agent: ${options.agent}. Must be one of: claude, codex`));
|
|
2526
2394
|
process.exit(1);
|
|
2527
2395
|
}
|
|
2528
2396
|
body.coding_agent = options.agent;
|
|
@@ -2534,21 +2402,21 @@ async function replicaSendCommand(id, options) {
|
|
|
2534
2402
|
body
|
|
2535
2403
|
}
|
|
2536
2404
|
);
|
|
2537
|
-
const statusColor = response.status === "sent" ?
|
|
2405
|
+
const statusColor = response.status === "sent" ? import_chalk15.default.green : import_chalk15.default.yellow;
|
|
2538
2406
|
console.log(statusColor(`
|
|
2539
2407
|
Message ${response.status}`));
|
|
2540
2408
|
if (response.position !== void 0 && response.position > 0) {
|
|
2541
|
-
console.log(
|
|
2409
|
+
console.log(import_chalk15.default.gray(` Queue position: ${response.position}`));
|
|
2542
2410
|
}
|
|
2543
2411
|
console.log();
|
|
2544
2412
|
} catch (error) {
|
|
2545
|
-
console.error(
|
|
2413
|
+
console.error(import_chalk15.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2546
2414
|
process.exit(1);
|
|
2547
2415
|
}
|
|
2548
2416
|
}
|
|
2549
2417
|
async function replicaDeleteCommand(id, options) {
|
|
2550
2418
|
if (!isAuthenticated()) {
|
|
2551
|
-
console.log(
|
|
2419
|
+
console.log(import_chalk15.default.red('Not logged in. Please run "replicas login" first.'));
|
|
2552
2420
|
process.exit(1);
|
|
2553
2421
|
}
|
|
2554
2422
|
try {
|
|
@@ -2560,24 +2428,24 @@ async function replicaDeleteCommand(id, options) {
|
|
|
2560
2428
|
initial: false
|
|
2561
2429
|
});
|
|
2562
2430
|
if (!response.confirm) {
|
|
2563
|
-
console.log(
|
|
2431
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2564
2432
|
return;
|
|
2565
2433
|
}
|
|
2566
2434
|
}
|
|
2567
2435
|
await orgAuthenticatedFetch(`/v1/replica/${id}`, {
|
|
2568
2436
|
method: "DELETE"
|
|
2569
2437
|
});
|
|
2570
|
-
console.log(
|
|
2438
|
+
console.log(import_chalk15.default.green(`
|
|
2571
2439
|
Replica ${id} deleted.
|
|
2572
2440
|
`));
|
|
2573
2441
|
} catch (error) {
|
|
2574
|
-
console.error(
|
|
2442
|
+
console.error(import_chalk15.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2575
2443
|
process.exit(1);
|
|
2576
2444
|
}
|
|
2577
2445
|
}
|
|
2578
2446
|
async function replicaReadCommand(id, options) {
|
|
2579
2447
|
if (!isAuthenticated()) {
|
|
2580
|
-
console.log(
|
|
2448
|
+
console.log(import_chalk15.default.red('Not logged in. Please run "replicas login" first.'));
|
|
2581
2449
|
process.exit(1);
|
|
2582
2450
|
}
|
|
2583
2451
|
try {
|
|
@@ -2589,79 +2457,79 @@ async function replicaReadCommand(id, options) {
|
|
|
2589
2457
|
`/v1/replica/${id}/read${query ? "?" + query : ""}`
|
|
2590
2458
|
);
|
|
2591
2459
|
if (response.waking) {
|
|
2592
|
-
console.log(
|
|
2460
|
+
console.log(import_chalk15.default.yellow("\nWorkspace is waking from sleep. Retry in 30-90 seconds.\n"));
|
|
2593
2461
|
return;
|
|
2594
2462
|
}
|
|
2595
|
-
console.log(
|
|
2463
|
+
console.log(import_chalk15.default.green(`
|
|
2596
2464
|
Conversation History
|
|
2597
2465
|
`));
|
|
2598
2466
|
if (response.coding_agent) {
|
|
2599
|
-
console.log(
|
|
2467
|
+
console.log(import_chalk15.default.gray(` Agent: ${response.coding_agent}`));
|
|
2600
2468
|
}
|
|
2601
2469
|
if (response.thread_id) {
|
|
2602
|
-
console.log(
|
|
2470
|
+
console.log(import_chalk15.default.gray(` Thread ID: ${response.thread_id}`));
|
|
2603
2471
|
}
|
|
2604
|
-
console.log(
|
|
2605
|
-
console.log(
|
|
2472
|
+
console.log(import_chalk15.default.gray(` Total Events: ${response.total}`));
|
|
2473
|
+
console.log(import_chalk15.default.gray(` Showing: ${response.events.length} events`));
|
|
2606
2474
|
if (response.hasMore) {
|
|
2607
|
-
console.log(
|
|
2475
|
+
console.log(import_chalk15.default.gray(` Has More: yes (use --offset to paginate)`));
|
|
2608
2476
|
}
|
|
2609
2477
|
console.log();
|
|
2610
2478
|
if (response.events.length === 0) {
|
|
2611
|
-
console.log(
|
|
2479
|
+
console.log(import_chalk15.default.yellow(" No events found.\n"));
|
|
2612
2480
|
return;
|
|
2613
2481
|
}
|
|
2614
|
-
console.log(
|
|
2482
|
+
console.log(import_chalk15.default.gray("-".repeat(60)));
|
|
2615
2483
|
const agentType = response.coding_agent || "claude";
|
|
2616
2484
|
const displayMessages = parseAgentEvents(response.events, agentType);
|
|
2617
2485
|
for (const message of displayMessages) {
|
|
2618
2486
|
formatDisplayMessage(message);
|
|
2619
2487
|
}
|
|
2620
|
-
console.log(
|
|
2488
|
+
console.log(import_chalk15.default.gray("\n" + "-".repeat(60)));
|
|
2621
2489
|
console.log();
|
|
2622
2490
|
} catch (error) {
|
|
2623
|
-
console.error(
|
|
2491
|
+
console.error(import_chalk15.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2624
2492
|
process.exit(1);
|
|
2625
2493
|
}
|
|
2626
2494
|
}
|
|
2627
2495
|
|
|
2628
2496
|
// src/commands/repositories.ts
|
|
2629
|
-
var
|
|
2497
|
+
var import_chalk16 = __toESM(require("chalk"));
|
|
2630
2498
|
function formatDate2(dateString) {
|
|
2631
2499
|
return new Date(dateString).toLocaleString();
|
|
2632
2500
|
}
|
|
2633
2501
|
async function repositoriesListCommand() {
|
|
2634
2502
|
if (!isAuthenticated()) {
|
|
2635
|
-
console.log(
|
|
2503
|
+
console.log(import_chalk16.default.red('Not logged in. Please run "replicas login" first.'));
|
|
2636
2504
|
process.exit(1);
|
|
2637
2505
|
}
|
|
2638
2506
|
try {
|
|
2639
2507
|
const response = await orgAuthenticatedFetch("/v1/repositories");
|
|
2640
2508
|
if (response.repositories.length === 0) {
|
|
2641
|
-
console.log(
|
|
2509
|
+
console.log(import_chalk16.default.yellow("\nNo repositories found.\n"));
|
|
2642
2510
|
return;
|
|
2643
2511
|
}
|
|
2644
|
-
console.log(
|
|
2512
|
+
console.log(import_chalk16.default.green(`
|
|
2645
2513
|
Repositories (${response.repositories.length}):
|
|
2646
2514
|
`));
|
|
2647
2515
|
for (const repo of response.repositories) {
|
|
2648
|
-
console.log(
|
|
2649
|
-
console.log(
|
|
2650
|
-
console.log(
|
|
2651
|
-
console.log(
|
|
2516
|
+
console.log(import_chalk16.default.white(` ${repo.name}`));
|
|
2517
|
+
console.log(import_chalk16.default.gray(` URL: ${repo.url}`));
|
|
2518
|
+
console.log(import_chalk16.default.gray(` Default Branch: ${repo.default_branch}`));
|
|
2519
|
+
console.log(import_chalk16.default.gray(` Created: ${formatDate2(repo.created_at)}`));
|
|
2652
2520
|
if (repo.github_repository_id) {
|
|
2653
|
-
console.log(
|
|
2521
|
+
console.log(import_chalk16.default.gray(` GitHub ID: ${repo.github_repository_id}`));
|
|
2654
2522
|
}
|
|
2655
2523
|
console.log();
|
|
2656
2524
|
}
|
|
2657
2525
|
} catch (error) {
|
|
2658
|
-
console.error(
|
|
2526
|
+
console.error(import_chalk16.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2659
2527
|
process.exit(1);
|
|
2660
2528
|
}
|
|
2661
2529
|
}
|
|
2662
2530
|
|
|
2663
2531
|
// src/index.ts
|
|
2664
|
-
var CLI_VERSION = "0.2.
|
|
2532
|
+
var CLI_VERSION = "0.2.29";
|
|
2665
2533
|
var program = new import_commander.Command();
|
|
2666
2534
|
program.name("replicas").description("CLI for managing Replicas workspaces").version(CLI_VERSION);
|
|
2667
2535
|
program.command("login").description("Authenticate with your Replicas account").action(async () => {
|
|
@@ -2669,7 +2537,7 @@ program.command("login").description("Authenticate with your Replicas account").
|
|
|
2669
2537
|
await loginCommand();
|
|
2670
2538
|
} catch (error) {
|
|
2671
2539
|
if (error instanceof Error) {
|
|
2672
|
-
console.error(
|
|
2540
|
+
console.error(import_chalk17.default.red(`
|
|
2673
2541
|
\u2717 ${error.message}
|
|
2674
2542
|
`));
|
|
2675
2543
|
}
|
|
@@ -2681,7 +2549,7 @@ program.command("init").description("Create a replicas.json configuration file")
|
|
|
2681
2549
|
initCommand(options);
|
|
2682
2550
|
} catch (error) {
|
|
2683
2551
|
if (error instanceof Error) {
|
|
2684
|
-
console.error(
|
|
2552
|
+
console.error(import_chalk17.default.red(`
|
|
2685
2553
|
\u2717 ${error.message}
|
|
2686
2554
|
`));
|
|
2687
2555
|
}
|
|
@@ -2693,7 +2561,7 @@ program.command("logout").description("Clear stored credentials").action(() => {
|
|
|
2693
2561
|
logoutCommand();
|
|
2694
2562
|
} catch (error) {
|
|
2695
2563
|
if (error instanceof Error) {
|
|
2696
|
-
console.error(
|
|
2564
|
+
console.error(import_chalk17.default.red(`
|
|
2697
2565
|
\u2717 ${error.message}
|
|
2698
2566
|
`));
|
|
2699
2567
|
}
|
|
@@ -2705,7 +2573,7 @@ program.command("whoami").description("Display current authenticated user").acti
|
|
|
2705
2573
|
await whoamiCommand();
|
|
2706
2574
|
} catch (error) {
|
|
2707
2575
|
if (error instanceof Error) {
|
|
2708
|
-
console.error(
|
|
2576
|
+
console.error(import_chalk17.default.red(`
|
|
2709
2577
|
\u2717 ${error.message}
|
|
2710
2578
|
`));
|
|
2711
2579
|
}
|
|
@@ -2717,7 +2585,7 @@ program.command("tools").description("List tools available on the Replicas Machi
|
|
|
2717
2585
|
await toolsCommand();
|
|
2718
2586
|
} catch (error) {
|
|
2719
2587
|
if (error instanceof Error) {
|
|
2720
|
-
console.error(
|
|
2588
|
+
console.error(import_chalk17.default.red(`
|
|
2721
2589
|
\u2717 ${error.message}
|
|
2722
2590
|
`));
|
|
2723
2591
|
}
|
|
@@ -2729,7 +2597,7 @@ program.command("codex-auth").description("Authenticate Replicas with your Codex
|
|
|
2729
2597
|
await codexAuthCommand(options);
|
|
2730
2598
|
} catch (error) {
|
|
2731
2599
|
if (error instanceof Error) {
|
|
2732
|
-
console.error(
|
|
2600
|
+
console.error(import_chalk17.default.red(`
|
|
2733
2601
|
\u2717 ${error.message}
|
|
2734
2602
|
`));
|
|
2735
2603
|
}
|
|
@@ -2741,7 +2609,7 @@ program.command("claude-auth").description("Authenticate Replicas with your Clau
|
|
|
2741
2609
|
await claudeAuthCommand(options);
|
|
2742
2610
|
} catch (error) {
|
|
2743
2611
|
if (error instanceof Error) {
|
|
2744
|
-
console.error(
|
|
2612
|
+
console.error(import_chalk17.default.red(`
|
|
2745
2613
|
\u2717 ${error.message}
|
|
2746
2614
|
`));
|
|
2747
2615
|
}
|
|
@@ -2754,7 +2622,7 @@ org.command("switch").description("Switch to a different organization").action(a
|
|
|
2754
2622
|
await orgSwitchCommand();
|
|
2755
2623
|
} catch (error) {
|
|
2756
2624
|
if (error instanceof Error) {
|
|
2757
|
-
console.error(
|
|
2625
|
+
console.error(import_chalk17.default.red(`
|
|
2758
2626
|
\u2717 ${error.message}
|
|
2759
2627
|
`));
|
|
2760
2628
|
}
|
|
@@ -2766,7 +2634,7 @@ org.action(async () => {
|
|
|
2766
2634
|
await orgCommand();
|
|
2767
2635
|
} catch (error) {
|
|
2768
2636
|
if (error instanceof Error) {
|
|
2769
|
-
console.error(
|
|
2637
|
+
console.error(import_chalk17.default.red(`
|
|
2770
2638
|
\u2717 ${error.message}
|
|
2771
2639
|
`));
|
|
2772
2640
|
}
|
|
@@ -2778,7 +2646,7 @@ program.command("connect <workspace-name>").description("Connect to a workspace
|
|
|
2778
2646
|
await connectCommand(workspaceName, options);
|
|
2779
2647
|
} catch (error) {
|
|
2780
2648
|
if (error instanceof Error) {
|
|
2781
|
-
console.error(
|
|
2649
|
+
console.error(import_chalk17.default.red(`
|
|
2782
2650
|
\u2717 ${error.message}
|
|
2783
2651
|
`));
|
|
2784
2652
|
}
|
|
@@ -2790,34 +2658,20 @@ program.command("code <workspace-name>").description("Open a workspace in VSCode
|
|
|
2790
2658
|
await codeCommand(workspaceName, options);
|
|
2791
2659
|
} catch (error) {
|
|
2792
2660
|
if (error instanceof Error) {
|
|
2793
|
-
console.error(
|
|
2661
|
+
console.error(import_chalk17.default.red(`
|
|
2794
2662
|
\u2717 ${error.message}
|
|
2795
2663
|
`));
|
|
2796
2664
|
}
|
|
2797
2665
|
process.exit(1);
|
|
2798
2666
|
}
|
|
2799
2667
|
});
|
|
2800
|
-
if (process.env.ENABLE_DEV_SYNC_COMMAND === "true") {
|
|
2801
|
-
program.command("dev-sync <workspace-name>").description("[Dev] Sync local engine to workspace VM").action(async (workspaceName) => {
|
|
2802
|
-
try {
|
|
2803
|
-
await devSyncCommand(workspaceName);
|
|
2804
|
-
} catch (error) {
|
|
2805
|
-
if (error instanceof Error) {
|
|
2806
|
-
console.error(import_chalk18.default.red(`
|
|
2807
|
-
\u2717 ${error.message}
|
|
2808
|
-
`));
|
|
2809
|
-
}
|
|
2810
|
-
process.exit(1);
|
|
2811
|
-
}
|
|
2812
|
-
});
|
|
2813
|
-
}
|
|
2814
2668
|
var config = program.command("config").description("Manage CLI configuration");
|
|
2815
2669
|
config.command("get <key>").description("Get a configuration value").action(async (key) => {
|
|
2816
2670
|
try {
|
|
2817
2671
|
await configGetCommand(key);
|
|
2818
2672
|
} catch (error) {
|
|
2819
2673
|
if (error instanceof Error) {
|
|
2820
|
-
console.error(
|
|
2674
|
+
console.error(import_chalk17.default.red(`
|
|
2821
2675
|
\u2717 ${error.message}
|
|
2822
2676
|
`));
|
|
2823
2677
|
}
|
|
@@ -2829,7 +2683,7 @@ config.command("set <key> <value>").description("Set a configuration value").act
|
|
|
2829
2683
|
await configSetCommand(key, value);
|
|
2830
2684
|
} catch (error) {
|
|
2831
2685
|
if (error instanceof Error) {
|
|
2832
|
-
console.error(
|
|
2686
|
+
console.error(import_chalk17.default.red(`
|
|
2833
2687
|
\u2717 ${error.message}
|
|
2834
2688
|
`));
|
|
2835
2689
|
}
|
|
@@ -2841,7 +2695,7 @@ config.command("list").description("List all configuration values").action(async
|
|
|
2841
2695
|
await configListCommand();
|
|
2842
2696
|
} catch (error) {
|
|
2843
2697
|
if (error instanceof Error) {
|
|
2844
|
-
console.error(
|
|
2698
|
+
console.error(import_chalk17.default.red(`
|
|
2845
2699
|
\u2717 ${error.message}
|
|
2846
2700
|
`));
|
|
2847
2701
|
}
|
|
@@ -2853,7 +2707,7 @@ program.command("list").description("List all replicas").option("-p, --page <pag
|
|
|
2853
2707
|
await replicaListCommand(options);
|
|
2854
2708
|
} catch (error) {
|
|
2855
2709
|
if (error instanceof Error) {
|
|
2856
|
-
console.error(
|
|
2710
|
+
console.error(import_chalk17.default.red(`
|
|
2857
2711
|
\u2717 ${error.message}
|
|
2858
2712
|
`));
|
|
2859
2713
|
}
|
|
@@ -2865,19 +2719,19 @@ program.command("get <id>").description("Get replica details by ID").action(asyn
|
|
|
2865
2719
|
await replicaGetCommand(id);
|
|
2866
2720
|
} catch (error) {
|
|
2867
2721
|
if (error instanceof Error) {
|
|
2868
|
-
console.error(
|
|
2722
|
+
console.error(import_chalk17.default.red(`
|
|
2869
2723
|
\u2717 ${error.message}
|
|
2870
2724
|
`));
|
|
2871
2725
|
}
|
|
2872
2726
|
process.exit(1);
|
|
2873
2727
|
}
|
|
2874
2728
|
});
|
|
2875
|
-
program.command("create [name]").description("Create a new replica").option("-m, --message <message>", "Initial message for the replica").option("-r, --repository <repository>", "Repository name").option("-
|
|
2729
|
+
program.command("create [name]").description("Create a new replica").option("-m, --message <message>", "Initial message for the replica").option("-r, --repository <repository>", "Repository name").option("-a, --agent <agent>", "Coding agent (claude, codex)").action(async (name, options) => {
|
|
2876
2730
|
try {
|
|
2877
2731
|
await replicaCreateCommand(name, options);
|
|
2878
2732
|
} catch (error) {
|
|
2879
2733
|
if (error instanceof Error) {
|
|
2880
|
-
console.error(
|
|
2734
|
+
console.error(import_chalk17.default.red(`
|
|
2881
2735
|
\u2717 ${error.message}
|
|
2882
2736
|
`));
|
|
2883
2737
|
}
|
|
@@ -2889,7 +2743,7 @@ program.command("send <id>").description("Send a message to a replica").option("
|
|
|
2889
2743
|
await replicaSendCommand(id, options);
|
|
2890
2744
|
} catch (error) {
|
|
2891
2745
|
if (error instanceof Error) {
|
|
2892
|
-
console.error(
|
|
2746
|
+
console.error(import_chalk17.default.red(`
|
|
2893
2747
|
\u2717 ${error.message}
|
|
2894
2748
|
`));
|
|
2895
2749
|
}
|
|
@@ -2901,7 +2755,7 @@ program.command("delete <id>").description("Delete a replica").option("-f, --for
|
|
|
2901
2755
|
await replicaDeleteCommand(id, options);
|
|
2902
2756
|
} catch (error) {
|
|
2903
2757
|
if (error instanceof Error) {
|
|
2904
|
-
console.error(
|
|
2758
|
+
console.error(import_chalk17.default.red(`
|
|
2905
2759
|
\u2717 ${error.message}
|
|
2906
2760
|
`));
|
|
2907
2761
|
}
|
|
@@ -2913,7 +2767,7 @@ program.command("read <id>").description("Read conversation history of a replica
|
|
|
2913
2767
|
await replicaReadCommand(id, options);
|
|
2914
2768
|
} catch (error) {
|
|
2915
2769
|
if (error instanceof Error) {
|
|
2916
|
-
console.error(
|
|
2770
|
+
console.error(import_chalk17.default.red(`
|
|
2917
2771
|
\u2717 ${error.message}
|
|
2918
2772
|
`));
|
|
2919
2773
|
}
|
|
@@ -2926,7 +2780,7 @@ repos.command("list").description("List all repositories").action(async () => {
|
|
|
2926
2780
|
await repositoriesListCommand();
|
|
2927
2781
|
} catch (error) {
|
|
2928
2782
|
if (error instanceof Error) {
|
|
2929
|
-
console.error(
|
|
2783
|
+
console.error(import_chalk17.default.red(`
|
|
2930
2784
|
\u2717 ${error.message}
|
|
2931
2785
|
`));
|
|
2932
2786
|
}
|
|
@@ -2938,7 +2792,7 @@ repos.action(async () => {
|
|
|
2938
2792
|
await repositoriesListCommand();
|
|
2939
2793
|
} catch (error) {
|
|
2940
2794
|
if (error instanceof Error) {
|
|
2941
|
-
console.error(
|
|
2795
|
+
console.error(import_chalk17.default.red(`
|
|
2942
2796
|
\u2717 ${error.message}
|
|
2943
2797
|
`));
|
|
2944
2798
|
}
|