replicas-cli 0.2.27 → 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 +200 -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,103 +2186,108 @@ 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;
|
|
2274
|
+
if (replicaName && /\s/.test(replicaName)) {
|
|
2275
|
+
console.log(import_chalk15.default.red("Replica name cannot contain spaces."));
|
|
2276
|
+
process.exit(1);
|
|
2277
|
+
}
|
|
2382
2278
|
if (!replicaName) {
|
|
2383
2279
|
const response2 = await (0, import_prompts3.default)({
|
|
2384
2280
|
type: "text",
|
|
2385
2281
|
name: "name",
|
|
2386
2282
|
message: "Enter replica name (without spaces):",
|
|
2387
|
-
validate: (value) =>
|
|
2283
|
+
validate: (value) => {
|
|
2284
|
+
if (!value.trim()) return "Name is required";
|
|
2285
|
+
if (/\s/.test(value)) return "Name cannot contain spaces";
|
|
2286
|
+
return true;
|
|
2287
|
+
}
|
|
2388
2288
|
});
|
|
2389
2289
|
if (!response2.name) {
|
|
2390
|
-
console.log(
|
|
2290
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2391
2291
|
return;
|
|
2392
2292
|
}
|
|
2393
2293
|
replicaName = response2.name;
|
|
@@ -2404,7 +2304,7 @@ async function replicaCreateCommand(name, options) {
|
|
|
2404
2304
|
}))
|
|
2405
2305
|
});
|
|
2406
2306
|
if (!response2.repository) {
|
|
2407
|
-
console.log(
|
|
2307
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2408
2308
|
return;
|
|
2409
2309
|
}
|
|
2410
2310
|
repository = response2.repository;
|
|
@@ -2417,29 +2317,11 @@ async function replicaCreateCommand(name, options) {
|
|
|
2417
2317
|
validate: (value) => value.trim() ? true : "Message is required"
|
|
2418
2318
|
});
|
|
2419
2319
|
if (!response2.message) {
|
|
2420
|
-
console.log(
|
|
2320
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2421
2321
|
return;
|
|
2422
2322
|
}
|
|
2423
2323
|
message = response2.message;
|
|
2424
2324
|
}
|
|
2425
|
-
if (!instanceType) {
|
|
2426
|
-
const response2 = await (0, import_prompts3.default)({
|
|
2427
|
-
type: "select",
|
|
2428
|
-
name: "instanceType",
|
|
2429
|
-
message: "Select instance type:",
|
|
2430
|
-
choices: [
|
|
2431
|
-
{ title: "Standard (2 vCPU, 4GB RAM)", value: "standard" },
|
|
2432
|
-
{ title: "Large (2 vCPU, 8GB RAM)", value: "large" },
|
|
2433
|
-
{ title: "Power (4 vCPU, 16GB RAM)", value: "power" }
|
|
2434
|
-
],
|
|
2435
|
-
initial: 0
|
|
2436
|
-
});
|
|
2437
|
-
if (!response2.instanceType) {
|
|
2438
|
-
console.log(import_chalk16.default.yellow("\nCancelled."));
|
|
2439
|
-
return;
|
|
2440
|
-
}
|
|
2441
|
-
instanceType = response2.instanceType;
|
|
2442
|
-
}
|
|
2443
2325
|
if (!codingAgent) {
|
|
2444
2326
|
const response2 = await (0, import_prompts3.default)({
|
|
2445
2327
|
type: "select",
|
|
@@ -2452,46 +2334,40 @@ async function replicaCreateCommand(name, options) {
|
|
|
2452
2334
|
initial: 0
|
|
2453
2335
|
});
|
|
2454
2336
|
if (!response2.agent) {
|
|
2455
|
-
console.log(
|
|
2337
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2456
2338
|
return;
|
|
2457
2339
|
}
|
|
2458
2340
|
codingAgent = response2.agent;
|
|
2459
2341
|
}
|
|
2460
|
-
if (!instanceType || !["standard", "large", "power"].includes(instanceType)) {
|
|
2461
|
-
console.log(import_chalk16.default.red(`Invalid instance type: ${instanceType}. Must be one of: standard, large, power`));
|
|
2462
|
-
process.exit(1);
|
|
2463
|
-
}
|
|
2464
2342
|
if (!codingAgent || !["claude", "codex"].includes(codingAgent)) {
|
|
2465
|
-
console.log(
|
|
2343
|
+
console.log(import_chalk15.default.red(`Invalid coding agent: ${codingAgent}. Must be one of: claude, codex`));
|
|
2466
2344
|
process.exit(1);
|
|
2467
2345
|
}
|
|
2468
2346
|
const body = {
|
|
2469
2347
|
name: replicaName,
|
|
2470
2348
|
message,
|
|
2471
2349
|
repository,
|
|
2472
|
-
instance_type: instanceType,
|
|
2473
2350
|
coding_agent: codingAgent
|
|
2474
2351
|
};
|
|
2475
|
-
console.log(
|
|
2352
|
+
console.log(import_chalk15.default.gray("\nCreating replica..."));
|
|
2476
2353
|
const response = await orgAuthenticatedFetch("/v1/replica", {
|
|
2477
2354
|
method: "POST",
|
|
2478
2355
|
body
|
|
2479
2356
|
});
|
|
2480
2357
|
const replica = response.replica;
|
|
2481
|
-
console.log(
|
|
2358
|
+
console.log(import_chalk15.default.green(`
|
|
2482
2359
|
Created replica: ${replica.name}`));
|
|
2483
|
-
console.log(
|
|
2484
|
-
console.log(
|
|
2485
|
-
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)}`));
|
|
2486
2362
|
console.log();
|
|
2487
2363
|
} catch (error) {
|
|
2488
|
-
console.error(
|
|
2364
|
+
console.error(import_chalk15.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2489
2365
|
process.exit(1);
|
|
2490
2366
|
}
|
|
2491
2367
|
}
|
|
2492
2368
|
async function replicaSendCommand(id, options) {
|
|
2493
2369
|
if (!isAuthenticated()) {
|
|
2494
|
-
console.log(
|
|
2370
|
+
console.log(import_chalk15.default.red('Not logged in. Please run "replicas login" first.'));
|
|
2495
2371
|
process.exit(1);
|
|
2496
2372
|
}
|
|
2497
2373
|
try {
|
|
@@ -2504,7 +2380,7 @@ async function replicaSendCommand(id, options) {
|
|
|
2504
2380
|
validate: (value) => value.trim() ? true : "Message is required"
|
|
2505
2381
|
});
|
|
2506
2382
|
if (!response2.message) {
|
|
2507
|
-
console.log(
|
|
2383
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2508
2384
|
return;
|
|
2509
2385
|
}
|
|
2510
2386
|
message = response2.message;
|
|
@@ -2514,7 +2390,7 @@ async function replicaSendCommand(id, options) {
|
|
|
2514
2390
|
};
|
|
2515
2391
|
if (options.agent) {
|
|
2516
2392
|
if (!["claude", "codex"].includes(options.agent)) {
|
|
2517
|
-
console.log(
|
|
2393
|
+
console.log(import_chalk15.default.red(`Invalid coding agent: ${options.agent}. Must be one of: claude, codex`));
|
|
2518
2394
|
process.exit(1);
|
|
2519
2395
|
}
|
|
2520
2396
|
body.coding_agent = options.agent;
|
|
@@ -2526,21 +2402,21 @@ async function replicaSendCommand(id, options) {
|
|
|
2526
2402
|
body
|
|
2527
2403
|
}
|
|
2528
2404
|
);
|
|
2529
|
-
const statusColor = response.status === "sent" ?
|
|
2405
|
+
const statusColor = response.status === "sent" ? import_chalk15.default.green : import_chalk15.default.yellow;
|
|
2530
2406
|
console.log(statusColor(`
|
|
2531
2407
|
Message ${response.status}`));
|
|
2532
2408
|
if (response.position !== void 0 && response.position > 0) {
|
|
2533
|
-
console.log(
|
|
2409
|
+
console.log(import_chalk15.default.gray(` Queue position: ${response.position}`));
|
|
2534
2410
|
}
|
|
2535
2411
|
console.log();
|
|
2536
2412
|
} catch (error) {
|
|
2537
|
-
console.error(
|
|
2413
|
+
console.error(import_chalk15.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2538
2414
|
process.exit(1);
|
|
2539
2415
|
}
|
|
2540
2416
|
}
|
|
2541
2417
|
async function replicaDeleteCommand(id, options) {
|
|
2542
2418
|
if (!isAuthenticated()) {
|
|
2543
|
-
console.log(
|
|
2419
|
+
console.log(import_chalk15.default.red('Not logged in. Please run "replicas login" first.'));
|
|
2544
2420
|
process.exit(1);
|
|
2545
2421
|
}
|
|
2546
2422
|
try {
|
|
@@ -2552,24 +2428,24 @@ async function replicaDeleteCommand(id, options) {
|
|
|
2552
2428
|
initial: false
|
|
2553
2429
|
});
|
|
2554
2430
|
if (!response.confirm) {
|
|
2555
|
-
console.log(
|
|
2431
|
+
console.log(import_chalk15.default.yellow("\nCancelled."));
|
|
2556
2432
|
return;
|
|
2557
2433
|
}
|
|
2558
2434
|
}
|
|
2559
2435
|
await orgAuthenticatedFetch(`/v1/replica/${id}`, {
|
|
2560
2436
|
method: "DELETE"
|
|
2561
2437
|
});
|
|
2562
|
-
console.log(
|
|
2438
|
+
console.log(import_chalk15.default.green(`
|
|
2563
2439
|
Replica ${id} deleted.
|
|
2564
2440
|
`));
|
|
2565
2441
|
} catch (error) {
|
|
2566
|
-
console.error(
|
|
2442
|
+
console.error(import_chalk15.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2567
2443
|
process.exit(1);
|
|
2568
2444
|
}
|
|
2569
2445
|
}
|
|
2570
2446
|
async function replicaReadCommand(id, options) {
|
|
2571
2447
|
if (!isAuthenticated()) {
|
|
2572
|
-
console.log(
|
|
2448
|
+
console.log(import_chalk15.default.red('Not logged in. Please run "replicas login" first.'));
|
|
2573
2449
|
process.exit(1);
|
|
2574
2450
|
}
|
|
2575
2451
|
try {
|
|
@@ -2581,79 +2457,79 @@ async function replicaReadCommand(id, options) {
|
|
|
2581
2457
|
`/v1/replica/${id}/read${query ? "?" + query : ""}`
|
|
2582
2458
|
);
|
|
2583
2459
|
if (response.waking) {
|
|
2584
|
-
console.log(
|
|
2460
|
+
console.log(import_chalk15.default.yellow("\nWorkspace is waking from sleep. Retry in 30-90 seconds.\n"));
|
|
2585
2461
|
return;
|
|
2586
2462
|
}
|
|
2587
|
-
console.log(
|
|
2463
|
+
console.log(import_chalk15.default.green(`
|
|
2588
2464
|
Conversation History
|
|
2589
2465
|
`));
|
|
2590
2466
|
if (response.coding_agent) {
|
|
2591
|
-
console.log(
|
|
2467
|
+
console.log(import_chalk15.default.gray(` Agent: ${response.coding_agent}`));
|
|
2592
2468
|
}
|
|
2593
2469
|
if (response.thread_id) {
|
|
2594
|
-
console.log(
|
|
2470
|
+
console.log(import_chalk15.default.gray(` Thread ID: ${response.thread_id}`));
|
|
2595
2471
|
}
|
|
2596
|
-
console.log(
|
|
2597
|
-
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`));
|
|
2598
2474
|
if (response.hasMore) {
|
|
2599
|
-
console.log(
|
|
2475
|
+
console.log(import_chalk15.default.gray(` Has More: yes (use --offset to paginate)`));
|
|
2600
2476
|
}
|
|
2601
2477
|
console.log();
|
|
2602
2478
|
if (response.events.length === 0) {
|
|
2603
|
-
console.log(
|
|
2479
|
+
console.log(import_chalk15.default.yellow(" No events found.\n"));
|
|
2604
2480
|
return;
|
|
2605
2481
|
}
|
|
2606
|
-
console.log(
|
|
2482
|
+
console.log(import_chalk15.default.gray("-".repeat(60)));
|
|
2607
2483
|
const agentType = response.coding_agent || "claude";
|
|
2608
2484
|
const displayMessages = parseAgentEvents(response.events, agentType);
|
|
2609
2485
|
for (const message of displayMessages) {
|
|
2610
2486
|
formatDisplayMessage(message);
|
|
2611
2487
|
}
|
|
2612
|
-
console.log(
|
|
2488
|
+
console.log(import_chalk15.default.gray("\n" + "-".repeat(60)));
|
|
2613
2489
|
console.log();
|
|
2614
2490
|
} catch (error) {
|
|
2615
|
-
console.error(
|
|
2491
|
+
console.error(import_chalk15.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2616
2492
|
process.exit(1);
|
|
2617
2493
|
}
|
|
2618
2494
|
}
|
|
2619
2495
|
|
|
2620
2496
|
// src/commands/repositories.ts
|
|
2621
|
-
var
|
|
2497
|
+
var import_chalk16 = __toESM(require("chalk"));
|
|
2622
2498
|
function formatDate2(dateString) {
|
|
2623
2499
|
return new Date(dateString).toLocaleString();
|
|
2624
2500
|
}
|
|
2625
2501
|
async function repositoriesListCommand() {
|
|
2626
2502
|
if (!isAuthenticated()) {
|
|
2627
|
-
console.log(
|
|
2503
|
+
console.log(import_chalk16.default.red('Not logged in. Please run "replicas login" first.'));
|
|
2628
2504
|
process.exit(1);
|
|
2629
2505
|
}
|
|
2630
2506
|
try {
|
|
2631
2507
|
const response = await orgAuthenticatedFetch("/v1/repositories");
|
|
2632
2508
|
if (response.repositories.length === 0) {
|
|
2633
|
-
console.log(
|
|
2509
|
+
console.log(import_chalk16.default.yellow("\nNo repositories found.\n"));
|
|
2634
2510
|
return;
|
|
2635
2511
|
}
|
|
2636
|
-
console.log(
|
|
2512
|
+
console.log(import_chalk16.default.green(`
|
|
2637
2513
|
Repositories (${response.repositories.length}):
|
|
2638
2514
|
`));
|
|
2639
2515
|
for (const repo of response.repositories) {
|
|
2640
|
-
console.log(
|
|
2641
|
-
console.log(
|
|
2642
|
-
console.log(
|
|
2643
|
-
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)}`));
|
|
2644
2520
|
if (repo.github_repository_id) {
|
|
2645
|
-
console.log(
|
|
2521
|
+
console.log(import_chalk16.default.gray(` GitHub ID: ${repo.github_repository_id}`));
|
|
2646
2522
|
}
|
|
2647
2523
|
console.log();
|
|
2648
2524
|
}
|
|
2649
2525
|
} catch (error) {
|
|
2650
|
-
console.error(
|
|
2526
|
+
console.error(import_chalk16.default.red(`Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
2651
2527
|
process.exit(1);
|
|
2652
2528
|
}
|
|
2653
2529
|
}
|
|
2654
2530
|
|
|
2655
2531
|
// src/index.ts
|
|
2656
|
-
var CLI_VERSION = "0.2.
|
|
2532
|
+
var CLI_VERSION = "0.2.29";
|
|
2657
2533
|
var program = new import_commander.Command();
|
|
2658
2534
|
program.name("replicas").description("CLI for managing Replicas workspaces").version(CLI_VERSION);
|
|
2659
2535
|
program.command("login").description("Authenticate with your Replicas account").action(async () => {
|
|
@@ -2661,7 +2537,7 @@ program.command("login").description("Authenticate with your Replicas account").
|
|
|
2661
2537
|
await loginCommand();
|
|
2662
2538
|
} catch (error) {
|
|
2663
2539
|
if (error instanceof Error) {
|
|
2664
|
-
console.error(
|
|
2540
|
+
console.error(import_chalk17.default.red(`
|
|
2665
2541
|
\u2717 ${error.message}
|
|
2666
2542
|
`));
|
|
2667
2543
|
}
|
|
@@ -2673,7 +2549,7 @@ program.command("init").description("Create a replicas.json configuration file")
|
|
|
2673
2549
|
initCommand(options);
|
|
2674
2550
|
} catch (error) {
|
|
2675
2551
|
if (error instanceof Error) {
|
|
2676
|
-
console.error(
|
|
2552
|
+
console.error(import_chalk17.default.red(`
|
|
2677
2553
|
\u2717 ${error.message}
|
|
2678
2554
|
`));
|
|
2679
2555
|
}
|
|
@@ -2685,7 +2561,7 @@ program.command("logout").description("Clear stored credentials").action(() => {
|
|
|
2685
2561
|
logoutCommand();
|
|
2686
2562
|
} catch (error) {
|
|
2687
2563
|
if (error instanceof Error) {
|
|
2688
|
-
console.error(
|
|
2564
|
+
console.error(import_chalk17.default.red(`
|
|
2689
2565
|
\u2717 ${error.message}
|
|
2690
2566
|
`));
|
|
2691
2567
|
}
|
|
@@ -2697,7 +2573,7 @@ program.command("whoami").description("Display current authenticated user").acti
|
|
|
2697
2573
|
await whoamiCommand();
|
|
2698
2574
|
} catch (error) {
|
|
2699
2575
|
if (error instanceof Error) {
|
|
2700
|
-
console.error(
|
|
2576
|
+
console.error(import_chalk17.default.red(`
|
|
2701
2577
|
\u2717 ${error.message}
|
|
2702
2578
|
`));
|
|
2703
2579
|
}
|
|
@@ -2709,7 +2585,7 @@ program.command("tools").description("List tools available on the Replicas Machi
|
|
|
2709
2585
|
await toolsCommand();
|
|
2710
2586
|
} catch (error) {
|
|
2711
2587
|
if (error instanceof Error) {
|
|
2712
|
-
console.error(
|
|
2588
|
+
console.error(import_chalk17.default.red(`
|
|
2713
2589
|
\u2717 ${error.message}
|
|
2714
2590
|
`));
|
|
2715
2591
|
}
|
|
@@ -2721,7 +2597,7 @@ program.command("codex-auth").description("Authenticate Replicas with your Codex
|
|
|
2721
2597
|
await codexAuthCommand(options);
|
|
2722
2598
|
} catch (error) {
|
|
2723
2599
|
if (error instanceof Error) {
|
|
2724
|
-
console.error(
|
|
2600
|
+
console.error(import_chalk17.default.red(`
|
|
2725
2601
|
\u2717 ${error.message}
|
|
2726
2602
|
`));
|
|
2727
2603
|
}
|
|
@@ -2733,7 +2609,7 @@ program.command("claude-auth").description("Authenticate Replicas with your Clau
|
|
|
2733
2609
|
await claudeAuthCommand(options);
|
|
2734
2610
|
} catch (error) {
|
|
2735
2611
|
if (error instanceof Error) {
|
|
2736
|
-
console.error(
|
|
2612
|
+
console.error(import_chalk17.default.red(`
|
|
2737
2613
|
\u2717 ${error.message}
|
|
2738
2614
|
`));
|
|
2739
2615
|
}
|
|
@@ -2746,7 +2622,7 @@ org.command("switch").description("Switch to a different organization").action(a
|
|
|
2746
2622
|
await orgSwitchCommand();
|
|
2747
2623
|
} catch (error) {
|
|
2748
2624
|
if (error instanceof Error) {
|
|
2749
|
-
console.error(
|
|
2625
|
+
console.error(import_chalk17.default.red(`
|
|
2750
2626
|
\u2717 ${error.message}
|
|
2751
2627
|
`));
|
|
2752
2628
|
}
|
|
@@ -2758,7 +2634,7 @@ org.action(async () => {
|
|
|
2758
2634
|
await orgCommand();
|
|
2759
2635
|
} catch (error) {
|
|
2760
2636
|
if (error instanceof Error) {
|
|
2761
|
-
console.error(
|
|
2637
|
+
console.error(import_chalk17.default.red(`
|
|
2762
2638
|
\u2717 ${error.message}
|
|
2763
2639
|
`));
|
|
2764
2640
|
}
|
|
@@ -2770,7 +2646,7 @@ program.command("connect <workspace-name>").description("Connect to a workspace
|
|
|
2770
2646
|
await connectCommand(workspaceName, options);
|
|
2771
2647
|
} catch (error) {
|
|
2772
2648
|
if (error instanceof Error) {
|
|
2773
|
-
console.error(
|
|
2649
|
+
console.error(import_chalk17.default.red(`
|
|
2774
2650
|
\u2717 ${error.message}
|
|
2775
2651
|
`));
|
|
2776
2652
|
}
|
|
@@ -2782,34 +2658,20 @@ program.command("code <workspace-name>").description("Open a workspace in VSCode
|
|
|
2782
2658
|
await codeCommand(workspaceName, options);
|
|
2783
2659
|
} catch (error) {
|
|
2784
2660
|
if (error instanceof Error) {
|
|
2785
|
-
console.error(
|
|
2661
|
+
console.error(import_chalk17.default.red(`
|
|
2786
2662
|
\u2717 ${error.message}
|
|
2787
2663
|
`));
|
|
2788
2664
|
}
|
|
2789
2665
|
process.exit(1);
|
|
2790
2666
|
}
|
|
2791
2667
|
});
|
|
2792
|
-
if (process.env.ENABLE_DEV_SYNC_COMMAND === "true") {
|
|
2793
|
-
program.command("dev-sync <workspace-name>").description("[Dev] Sync local engine to workspace VM").action(async (workspaceName) => {
|
|
2794
|
-
try {
|
|
2795
|
-
await devSyncCommand(workspaceName);
|
|
2796
|
-
} catch (error) {
|
|
2797
|
-
if (error instanceof Error) {
|
|
2798
|
-
console.error(import_chalk18.default.red(`
|
|
2799
|
-
\u2717 ${error.message}
|
|
2800
|
-
`));
|
|
2801
|
-
}
|
|
2802
|
-
process.exit(1);
|
|
2803
|
-
}
|
|
2804
|
-
});
|
|
2805
|
-
}
|
|
2806
2668
|
var config = program.command("config").description("Manage CLI configuration");
|
|
2807
2669
|
config.command("get <key>").description("Get a configuration value").action(async (key) => {
|
|
2808
2670
|
try {
|
|
2809
2671
|
await configGetCommand(key);
|
|
2810
2672
|
} catch (error) {
|
|
2811
2673
|
if (error instanceof Error) {
|
|
2812
|
-
console.error(
|
|
2674
|
+
console.error(import_chalk17.default.red(`
|
|
2813
2675
|
\u2717 ${error.message}
|
|
2814
2676
|
`));
|
|
2815
2677
|
}
|
|
@@ -2821,7 +2683,7 @@ config.command("set <key> <value>").description("Set a configuration value").act
|
|
|
2821
2683
|
await configSetCommand(key, value);
|
|
2822
2684
|
} catch (error) {
|
|
2823
2685
|
if (error instanceof Error) {
|
|
2824
|
-
console.error(
|
|
2686
|
+
console.error(import_chalk17.default.red(`
|
|
2825
2687
|
\u2717 ${error.message}
|
|
2826
2688
|
`));
|
|
2827
2689
|
}
|
|
@@ -2833,7 +2695,7 @@ config.command("list").description("List all configuration values").action(async
|
|
|
2833
2695
|
await configListCommand();
|
|
2834
2696
|
} catch (error) {
|
|
2835
2697
|
if (error instanceof Error) {
|
|
2836
|
-
console.error(
|
|
2698
|
+
console.error(import_chalk17.default.red(`
|
|
2837
2699
|
\u2717 ${error.message}
|
|
2838
2700
|
`));
|
|
2839
2701
|
}
|
|
@@ -2845,7 +2707,7 @@ program.command("list").description("List all replicas").option("-p, --page <pag
|
|
|
2845
2707
|
await replicaListCommand(options);
|
|
2846
2708
|
} catch (error) {
|
|
2847
2709
|
if (error instanceof Error) {
|
|
2848
|
-
console.error(
|
|
2710
|
+
console.error(import_chalk17.default.red(`
|
|
2849
2711
|
\u2717 ${error.message}
|
|
2850
2712
|
`));
|
|
2851
2713
|
}
|
|
@@ -2857,19 +2719,19 @@ program.command("get <id>").description("Get replica details by ID").action(asyn
|
|
|
2857
2719
|
await replicaGetCommand(id);
|
|
2858
2720
|
} catch (error) {
|
|
2859
2721
|
if (error instanceof Error) {
|
|
2860
|
-
console.error(
|
|
2722
|
+
console.error(import_chalk17.default.red(`
|
|
2861
2723
|
\u2717 ${error.message}
|
|
2862
2724
|
`));
|
|
2863
2725
|
}
|
|
2864
2726
|
process.exit(1);
|
|
2865
2727
|
}
|
|
2866
2728
|
});
|
|
2867
|
-
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) => {
|
|
2868
2730
|
try {
|
|
2869
2731
|
await replicaCreateCommand(name, options);
|
|
2870
2732
|
} catch (error) {
|
|
2871
2733
|
if (error instanceof Error) {
|
|
2872
|
-
console.error(
|
|
2734
|
+
console.error(import_chalk17.default.red(`
|
|
2873
2735
|
\u2717 ${error.message}
|
|
2874
2736
|
`));
|
|
2875
2737
|
}
|
|
@@ -2881,7 +2743,7 @@ program.command("send <id>").description("Send a message to a replica").option("
|
|
|
2881
2743
|
await replicaSendCommand(id, options);
|
|
2882
2744
|
} catch (error) {
|
|
2883
2745
|
if (error instanceof Error) {
|
|
2884
|
-
console.error(
|
|
2746
|
+
console.error(import_chalk17.default.red(`
|
|
2885
2747
|
\u2717 ${error.message}
|
|
2886
2748
|
`));
|
|
2887
2749
|
}
|
|
@@ -2893,7 +2755,7 @@ program.command("delete <id>").description("Delete a replica").option("-f, --for
|
|
|
2893
2755
|
await replicaDeleteCommand(id, options);
|
|
2894
2756
|
} catch (error) {
|
|
2895
2757
|
if (error instanceof Error) {
|
|
2896
|
-
console.error(
|
|
2758
|
+
console.error(import_chalk17.default.red(`
|
|
2897
2759
|
\u2717 ${error.message}
|
|
2898
2760
|
`));
|
|
2899
2761
|
}
|
|
@@ -2905,7 +2767,7 @@ program.command("read <id>").description("Read conversation history of a replica
|
|
|
2905
2767
|
await replicaReadCommand(id, options);
|
|
2906
2768
|
} catch (error) {
|
|
2907
2769
|
if (error instanceof Error) {
|
|
2908
|
-
console.error(
|
|
2770
|
+
console.error(import_chalk17.default.red(`
|
|
2909
2771
|
\u2717 ${error.message}
|
|
2910
2772
|
`));
|
|
2911
2773
|
}
|
|
@@ -2918,7 +2780,7 @@ repos.command("list").description("List all repositories").action(async () => {
|
|
|
2918
2780
|
await repositoriesListCommand();
|
|
2919
2781
|
} catch (error) {
|
|
2920
2782
|
if (error instanceof Error) {
|
|
2921
|
-
console.error(
|
|
2783
|
+
console.error(import_chalk17.default.red(`
|
|
2922
2784
|
\u2717 ${error.message}
|
|
2923
2785
|
`));
|
|
2924
2786
|
}
|
|
@@ -2930,7 +2792,7 @@ repos.action(async () => {
|
|
|
2930
2792
|
await repositoriesListCommand();
|
|
2931
2793
|
} catch (error) {
|
|
2932
2794
|
if (error instanceof Error) {
|
|
2933
|
-
console.error(
|
|
2795
|
+
console.error(import_chalk17.default.red(`
|
|
2934
2796
|
\u2717 ${error.message}
|
|
2935
2797
|
`));
|
|
2936
2798
|
}
|