@waniwani/cli 0.0.41 → 0.0.43
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/README.md +3 -2
- package/dist/index.js +551 -342
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { createRequire } from "module";
|
|
5
|
-
import { Command as
|
|
5
|
+
import { Command as Command25 } from "commander";
|
|
6
6
|
|
|
7
7
|
// src/commands/config/index.ts
|
|
8
8
|
import { Command as Command2 } from "commander";
|
|
@@ -350,6 +350,36 @@ var AuthManager = class {
|
|
|
350
350
|
var auth = new AuthManager();
|
|
351
351
|
|
|
352
352
|
// src/commands/login.ts
|
|
353
|
+
var LOGO_LINES = [
|
|
354
|
+
"\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557",
|
|
355
|
+
"\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551",
|
|
356
|
+
"\u2588\u2588\u2551 \u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551",
|
|
357
|
+
"\u2588\u2588\u2551\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551",
|
|
358
|
+
"\u255A\u2588\u2588\u2588\u2554\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2554\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551",
|
|
359
|
+
" \u255A\u2550\u2550\u255D\u255A\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u255D\u255A\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D"
|
|
360
|
+
];
|
|
361
|
+
var LOGO_COLORS = [
|
|
362
|
+
"\x1B[38;5;223m",
|
|
363
|
+
// light peach
|
|
364
|
+
"\x1B[38;5;216m",
|
|
365
|
+
// peach
|
|
366
|
+
"\x1B[38;5;209m",
|
|
367
|
+
// salmon
|
|
368
|
+
"\x1B[38;5;203m",
|
|
369
|
+
// coral
|
|
370
|
+
"\x1B[38;5;167m",
|
|
371
|
+
// warm red
|
|
372
|
+
"\x1B[38;5;131m"
|
|
373
|
+
// deep terracotta
|
|
374
|
+
];
|
|
375
|
+
var RESET = "\x1B[0m";
|
|
376
|
+
function showLogo() {
|
|
377
|
+
console.log();
|
|
378
|
+
for (let i = 0; i < LOGO_LINES.length; i++) {
|
|
379
|
+
console.log(`${LOGO_COLORS[i]}${LOGO_LINES[i]}${RESET}`);
|
|
380
|
+
}
|
|
381
|
+
console.log();
|
|
382
|
+
}
|
|
353
383
|
var CALLBACK_PORT = 54321;
|
|
354
384
|
var CALLBACK_URL = `http://localhost:${CALLBACK_PORT}/callback`;
|
|
355
385
|
var CLIENT_NAME = "waniwani-cli";
|
|
@@ -662,7 +692,7 @@ var loginCommand = new Command3("login").description("Log in to WaniWani").optio
|
|
|
662
692
|
}
|
|
663
693
|
}
|
|
664
694
|
if (!json) {
|
|
665
|
-
|
|
695
|
+
showLogo();
|
|
666
696
|
}
|
|
667
697
|
const spinner = ora("Registering client...").start();
|
|
668
698
|
const { client_id: clientId } = await registerClient();
|
|
@@ -757,11 +787,13 @@ var logoutCommand = new Command4("logout").description("Log out from WaniWani").
|
|
|
757
787
|
});
|
|
758
788
|
|
|
759
789
|
// src/commands/mcp/index.ts
|
|
760
|
-
import { Command as
|
|
790
|
+
import { Command as Command21 } from "commander";
|
|
761
791
|
|
|
762
|
-
// src/commands/mcp/
|
|
763
|
-
import {
|
|
764
|
-
import
|
|
792
|
+
// src/commands/mcp/clone.ts
|
|
793
|
+
import { execSync } from "child_process";
|
|
794
|
+
import { existsSync as existsSync3 } from "fs";
|
|
795
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
796
|
+
import { join as join3 } from "path";
|
|
765
797
|
import { Command as Command5 } from "commander";
|
|
766
798
|
import ora2 from "ora";
|
|
767
799
|
|
|
@@ -853,13 +885,221 @@ var api = {
|
|
|
853
885
|
getBaseUrl: () => config.getApiUrl()
|
|
854
886
|
};
|
|
855
887
|
|
|
888
|
+
// src/commands/mcp/clone.ts
|
|
889
|
+
async function loadParentConfig(cwd) {
|
|
890
|
+
const parentConfigPath = join3(cwd, LOCAL_CONFIG_DIR, CONFIG_FILE_NAME);
|
|
891
|
+
if (!existsSync3(parentConfigPath)) {
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
894
|
+
try {
|
|
895
|
+
const content = await readFile2(parentConfigPath, "utf-8");
|
|
896
|
+
const config2 = JSON.parse(content);
|
|
897
|
+
const { mcpId: _, sessionId: __, ...rest } = config2;
|
|
898
|
+
return rest;
|
|
899
|
+
} catch {
|
|
900
|
+
return null;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
function checkGitInstalled() {
|
|
904
|
+
try {
|
|
905
|
+
execSync("git --version", { stdio: "ignore" });
|
|
906
|
+
} catch {
|
|
907
|
+
throw new CLIError(
|
|
908
|
+
"git is required but not found. Install it from https://git-scm.com/",
|
|
909
|
+
"GIT_NOT_FOUND"
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
var cloneCommand = new Command5("clone").description("Clone an existing MCP project to a local directory").argument("<name>", "Name of the MCP to clone").argument("[directory]", "Directory to clone into (defaults to MCP name)").action(async (name, directory, command) => {
|
|
914
|
+
const globalOptions = command.optsWithGlobals();
|
|
915
|
+
const json = globalOptions.json ?? false;
|
|
916
|
+
try {
|
|
917
|
+
const cwd = process.cwd();
|
|
918
|
+
const dirName = directory ?? name;
|
|
919
|
+
const projectDir = join3(cwd, dirName);
|
|
920
|
+
if (existsSync3(projectDir)) {
|
|
921
|
+
if (json) {
|
|
922
|
+
formatOutput(
|
|
923
|
+
{
|
|
924
|
+
success: false,
|
|
925
|
+
error: `Directory "${dirName}" already exists`
|
|
926
|
+
},
|
|
927
|
+
true
|
|
928
|
+
);
|
|
929
|
+
} else {
|
|
930
|
+
console.error(`Error: Directory "${dirName}" already exists`);
|
|
931
|
+
}
|
|
932
|
+
process.exit(1);
|
|
933
|
+
}
|
|
934
|
+
checkGitInstalled();
|
|
935
|
+
const spinner = ora2("Fetching MCPs...").start();
|
|
936
|
+
const mcps = await api.get(
|
|
937
|
+
"/api/mcp/repositories"
|
|
938
|
+
);
|
|
939
|
+
const mcp = mcps.find((m) => m.name === name);
|
|
940
|
+
if (!mcp) {
|
|
941
|
+
spinner.fail("MCP not found");
|
|
942
|
+
throw new McpError(
|
|
943
|
+
`MCP "${name}" not found. Run 'waniwani mcp list' to see available MCPs.`
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
spinner.text = "Cloning repository...";
|
|
947
|
+
const { cloneUrl } = await api.get(
|
|
948
|
+
`/api/mcp/repositories/${mcp.id}/clone-url`
|
|
949
|
+
);
|
|
950
|
+
try {
|
|
951
|
+
execSync(`git clone "${cloneUrl}" "${projectDir}"`, {
|
|
952
|
+
stdio: "ignore"
|
|
953
|
+
});
|
|
954
|
+
} catch {
|
|
955
|
+
spinner.fail("Failed to clone repository");
|
|
956
|
+
throw new CLIError(
|
|
957
|
+
"Failed to clone repository. Ensure git is configured correctly.",
|
|
958
|
+
"CLONE_FAILED"
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
const parentConfig = await loadParentConfig(cwd);
|
|
962
|
+
await initConfigAt(projectDir, {
|
|
963
|
+
...parentConfig,
|
|
964
|
+
mcpId: mcp.id
|
|
965
|
+
});
|
|
966
|
+
spinner.succeed("Repository cloned");
|
|
967
|
+
if (json) {
|
|
968
|
+
formatOutput(
|
|
969
|
+
{
|
|
970
|
+
success: true,
|
|
971
|
+
projectDir,
|
|
972
|
+
mcpId: mcp.id
|
|
973
|
+
},
|
|
974
|
+
true
|
|
975
|
+
);
|
|
976
|
+
} else {
|
|
977
|
+
console.log();
|
|
978
|
+
formatSuccess(`MCP "${name}" cloned!`, false);
|
|
979
|
+
console.log();
|
|
980
|
+
console.log("Next steps:");
|
|
981
|
+
console.log(` cd ${dirName}`);
|
|
982
|
+
console.log(" waniwani mcp preview # Start developing");
|
|
983
|
+
}
|
|
984
|
+
} catch (error) {
|
|
985
|
+
handleError(error, json);
|
|
986
|
+
process.exit(1);
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
// src/commands/mcp/create.ts
|
|
991
|
+
import { execSync as execSync2 } from "child_process";
|
|
992
|
+
import { existsSync as existsSync4 } from "fs";
|
|
993
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
994
|
+
import { join as join4 } from "path";
|
|
995
|
+
import { Command as Command6 } from "commander";
|
|
996
|
+
import ora3 from "ora";
|
|
997
|
+
async function loadParentConfig2(cwd) {
|
|
998
|
+
const parentConfigPath = join4(cwd, LOCAL_CONFIG_DIR, CONFIG_FILE_NAME);
|
|
999
|
+
if (!existsSync4(parentConfigPath)) {
|
|
1000
|
+
return null;
|
|
1001
|
+
}
|
|
1002
|
+
try {
|
|
1003
|
+
const content = await readFile3(parentConfigPath, "utf-8");
|
|
1004
|
+
const config2 = JSON.parse(content);
|
|
1005
|
+
const { mcpId: _, sessionId: __, ...rest } = config2;
|
|
1006
|
+
return rest;
|
|
1007
|
+
} catch {
|
|
1008
|
+
return null;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
function checkGitInstalled2() {
|
|
1012
|
+
try {
|
|
1013
|
+
execSync2("git --version", { stdio: "ignore" });
|
|
1014
|
+
} catch {
|
|
1015
|
+
throw new CLIError(
|
|
1016
|
+
"git is required but not found. Install it from https://git-scm.com/",
|
|
1017
|
+
"GIT_NOT_FOUND"
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
var createCommand = new Command6("create").description("Create a new MCP project").argument("<name>", "Name for the MCP project").action(async (name, _options, command) => {
|
|
1022
|
+
const globalOptions = command.optsWithGlobals();
|
|
1023
|
+
const json = globalOptions.json ?? false;
|
|
1024
|
+
try {
|
|
1025
|
+
const cwd = process.cwd();
|
|
1026
|
+
const projectDir = join4(cwd, name);
|
|
1027
|
+
if (existsSync4(projectDir)) {
|
|
1028
|
+
if (json) {
|
|
1029
|
+
formatOutput(
|
|
1030
|
+
{
|
|
1031
|
+
success: false,
|
|
1032
|
+
error: `Directory "${name}" already exists`
|
|
1033
|
+
},
|
|
1034
|
+
true
|
|
1035
|
+
);
|
|
1036
|
+
} else {
|
|
1037
|
+
console.error(`Error: Directory "${name}" already exists`);
|
|
1038
|
+
}
|
|
1039
|
+
process.exit(1);
|
|
1040
|
+
}
|
|
1041
|
+
checkGitInstalled2();
|
|
1042
|
+
const spinner = ora3("Creating MCP...").start();
|
|
1043
|
+
const result = await api.post("/api/mcp/repositories", {
|
|
1044
|
+
name
|
|
1045
|
+
});
|
|
1046
|
+
spinner.text = "Cloning repository...";
|
|
1047
|
+
const { cloneUrl } = await api.get(
|
|
1048
|
+
`/api/mcp/repositories/${result.id}/clone-url`
|
|
1049
|
+
);
|
|
1050
|
+
try {
|
|
1051
|
+
execSync2(`git clone "${cloneUrl}" "${projectDir}"`, {
|
|
1052
|
+
stdio: "ignore"
|
|
1053
|
+
});
|
|
1054
|
+
} catch {
|
|
1055
|
+
spinner.fail("Failed to clone repository");
|
|
1056
|
+
throw new CLIError(
|
|
1057
|
+
`Failed to clone repository. Ensure git is configured correctly.`,
|
|
1058
|
+
"CLONE_FAILED"
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
const parentConfig = await loadParentConfig2(cwd);
|
|
1062
|
+
await initConfigAt(projectDir, {
|
|
1063
|
+
...parentConfig,
|
|
1064
|
+
mcpId: result.id
|
|
1065
|
+
});
|
|
1066
|
+
spinner.succeed("MCP project created");
|
|
1067
|
+
if (json) {
|
|
1068
|
+
formatOutput(
|
|
1069
|
+
{
|
|
1070
|
+
success: true,
|
|
1071
|
+
projectDir,
|
|
1072
|
+
mcpId: result.id
|
|
1073
|
+
},
|
|
1074
|
+
true
|
|
1075
|
+
);
|
|
1076
|
+
} else {
|
|
1077
|
+
console.log();
|
|
1078
|
+
formatSuccess(`MCP "${name}" created!`, false);
|
|
1079
|
+
console.log();
|
|
1080
|
+
console.log("Next steps:");
|
|
1081
|
+
console.log(` cd ${name}`);
|
|
1082
|
+
console.log(" waniwani mcp preview # Start developing");
|
|
1083
|
+
}
|
|
1084
|
+
} catch (error) {
|
|
1085
|
+
handleError(error, json);
|
|
1086
|
+
process.exit(1);
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
// src/commands/mcp/delete.ts
|
|
1091
|
+
import { confirm } from "@inquirer/prompts";
|
|
1092
|
+
import chalk4 from "chalk";
|
|
1093
|
+
import { Command as Command7 } from "commander";
|
|
1094
|
+
import ora4 from "ora";
|
|
1095
|
+
|
|
856
1096
|
// src/lib/utils.ts
|
|
857
1097
|
async function requireMcpId(mcpId) {
|
|
858
1098
|
if (mcpId) return mcpId;
|
|
859
1099
|
const configMcpId = await config.getMcpId();
|
|
860
1100
|
if (!configMcpId) {
|
|
861
1101
|
throw new McpError(
|
|
862
|
-
"No active MCP. Run 'waniwani mcp
|
|
1102
|
+
"No active MCP. Run 'waniwani mcp create <name>' or 'waniwani mcp use <name>'."
|
|
863
1103
|
);
|
|
864
1104
|
}
|
|
865
1105
|
return configMcpId;
|
|
@@ -911,7 +1151,7 @@ function detectBinary(buffer) {
|
|
|
911
1151
|
}
|
|
912
1152
|
|
|
913
1153
|
// src/commands/mcp/delete.ts
|
|
914
|
-
var deleteCommand = new
|
|
1154
|
+
var deleteCommand = new Command7("delete").description("Delete the MCP (includes all associated resources)").option("--mcp-id <id>", "Specific MCP ID").option("--force", "Skip confirmation prompt").action(async (options, command) => {
|
|
915
1155
|
const globalOptions = command.optsWithGlobals();
|
|
916
1156
|
const json = globalOptions.json ?? false;
|
|
917
1157
|
try {
|
|
@@ -936,7 +1176,7 @@ var deleteCommand = new Command5("delete").description("Delete the MCP (includes
|
|
|
936
1176
|
return;
|
|
937
1177
|
}
|
|
938
1178
|
}
|
|
939
|
-
const spinner =
|
|
1179
|
+
const spinner = ora4("Deleting MCP...").start();
|
|
940
1180
|
await api.delete(`/api/mcp/repositories/${mcpId}`);
|
|
941
1181
|
spinner.succeed("MCP deleted");
|
|
942
1182
|
if (await config.getMcpId() === mcpId) {
|
|
@@ -955,19 +1195,19 @@ var deleteCommand = new Command5("delete").description("Delete the MCP (includes
|
|
|
955
1195
|
});
|
|
956
1196
|
|
|
957
1197
|
// src/commands/mcp/file/index.ts
|
|
958
|
-
import { Command as
|
|
1198
|
+
import { Command as Command11 } from "commander";
|
|
959
1199
|
|
|
960
1200
|
// src/commands/mcp/file/list.ts
|
|
961
1201
|
import chalk5 from "chalk";
|
|
962
|
-
import { Command as
|
|
963
|
-
import
|
|
964
|
-
var listCommand = new
|
|
1202
|
+
import { Command as Command8 } from "commander";
|
|
1203
|
+
import ora5 from "ora";
|
|
1204
|
+
var listCommand = new Command8("list").description("List files in the MCP sandbox").argument("[path]", "Directory path (defaults to /app)", "/app").option("--mcp-id <id>", "Specific MCP ID").action(async (path, options, command) => {
|
|
965
1205
|
const globalOptions = command.optsWithGlobals();
|
|
966
1206
|
const json = globalOptions.json ?? false;
|
|
967
1207
|
try {
|
|
968
1208
|
await requireMcpId(options.mcpId);
|
|
969
1209
|
const sessionId = await requireSessionId();
|
|
970
|
-
const spinner =
|
|
1210
|
+
const spinner = ora5(`Listing ${path}...`).start();
|
|
971
1211
|
const result = await api.get(
|
|
972
1212
|
`/api/mcp/sessions/${sessionId}/files/list?path=${encodeURIComponent(path)}`
|
|
973
1213
|
);
|
|
@@ -1004,16 +1244,16 @@ function formatSize(bytes) {
|
|
|
1004
1244
|
|
|
1005
1245
|
// src/commands/mcp/file/read.ts
|
|
1006
1246
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
1007
|
-
import { Command as
|
|
1008
|
-
import
|
|
1009
|
-
var readCommand = new
|
|
1247
|
+
import { Command as Command9 } from "commander";
|
|
1248
|
+
import ora6 from "ora";
|
|
1249
|
+
var readCommand = new Command9("read").description("Read a file from the MCP sandbox").argument("<path>", "Path in sandbox (e.g., /app/src/index.ts)").option("--mcp-id <id>", "Specific MCP ID").option("--output <file>", "Write to local file instead of stdout").option("--base64", "Output as base64 (for binary files)").action(async (path, options, command) => {
|
|
1010
1250
|
const globalOptions = command.optsWithGlobals();
|
|
1011
1251
|
const json = globalOptions.json ?? false;
|
|
1012
1252
|
try {
|
|
1013
1253
|
await requireMcpId(options.mcpId);
|
|
1014
1254
|
const sessionId = await requireSessionId();
|
|
1015
1255
|
const encoding = options.base64 ? "base64" : "utf8";
|
|
1016
|
-
const spinner =
|
|
1256
|
+
const spinner = ora6(`Reading ${path}...`).start();
|
|
1017
1257
|
const result = await api.get(
|
|
1018
1258
|
`/api/mcp/sessions/${sessionId}/files?path=${encodeURIComponent(path)}&encoding=${encoding}`
|
|
1019
1259
|
);
|
|
@@ -1044,10 +1284,10 @@ var readCommand = new Command7("read").description("Read a file from the MCP san
|
|
|
1044
1284
|
});
|
|
1045
1285
|
|
|
1046
1286
|
// src/commands/mcp/file/write.ts
|
|
1047
|
-
import { readFile as
|
|
1048
|
-
import { Command as
|
|
1049
|
-
import
|
|
1050
|
-
var writeCommand = new
|
|
1287
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
1288
|
+
import { Command as Command10 } from "commander";
|
|
1289
|
+
import ora7 from "ora";
|
|
1290
|
+
var writeCommand = new Command10("write").description("Write a file to the MCP sandbox").argument("<path>", "Path in sandbox (e.g., /app/src/index.ts)").option("--mcp-id <id>", "Specific MCP ID").option("--content <content>", "Content to write").option("--file <localFile>", "Local file to upload").option("--base64", "Treat content as base64 encoded").action(async (path, options, command) => {
|
|
1051
1291
|
const globalOptions = command.optsWithGlobals();
|
|
1052
1292
|
const json = globalOptions.json ?? false;
|
|
1053
1293
|
try {
|
|
@@ -1061,7 +1301,7 @@ var writeCommand = new Command8("write").description("Write a file to the MCP sa
|
|
|
1061
1301
|
encoding = "base64";
|
|
1062
1302
|
}
|
|
1063
1303
|
} else if (options.file) {
|
|
1064
|
-
const fileBuffer = await
|
|
1304
|
+
const fileBuffer = await readFile4(options.file);
|
|
1065
1305
|
if (options.base64) {
|
|
1066
1306
|
content = fileBuffer.toString("base64");
|
|
1067
1307
|
encoding = "base64";
|
|
@@ -1074,7 +1314,7 @@ var writeCommand = new Command8("write").description("Write a file to the MCP sa
|
|
|
1074
1314
|
"MISSING_CONTENT"
|
|
1075
1315
|
);
|
|
1076
1316
|
}
|
|
1077
|
-
const spinner =
|
|
1317
|
+
const spinner = ora7(`Writing ${path}...`).start();
|
|
1078
1318
|
const result = await api.post(
|
|
1079
1319
|
`/api/mcp/sessions/${sessionId}/files`,
|
|
1080
1320
|
{
|
|
@@ -1094,275 +1334,73 @@ var writeCommand = new Command8("write").description("Write a file to the MCP sa
|
|
|
1094
1334
|
});
|
|
1095
1335
|
|
|
1096
1336
|
// src/commands/mcp/file/index.ts
|
|
1097
|
-
var fileCommand = new
|
|
1098
|
-
|
|
1099
|
-
// src/commands/mcp/init.ts
|
|
1100
|
-
import { existsSync as existsSync4, mkdirSync } from "fs";
|
|
1101
|
-
import { readFile as readFile4 } from "fs/promises";
|
|
1102
|
-
import { join as join4 } from "path";
|
|
1103
|
-
import { Command as Command10 } from "commander";
|
|
1104
|
-
import ora6 from "ora";
|
|
1337
|
+
var fileCommand = new Command11("file").description("File operations in MCP sandbox").addCommand(readCommand).addCommand(writeCommand).addCommand(listCommand);
|
|
1105
1338
|
|
|
1106
|
-
// src/
|
|
1107
|
-
import
|
|
1108
|
-
import {
|
|
1109
|
-
import
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1339
|
+
// src/commands/mcp/list.ts
|
|
1340
|
+
import chalk6 from "chalk";
|
|
1341
|
+
import { Command as Command12 } from "commander";
|
|
1342
|
+
import ora8 from "ora";
|
|
1343
|
+
var listCommand2 = new Command12("list").description("List all MCPs in your organization").action(async (_, command) => {
|
|
1344
|
+
const globalOptions = command.optsWithGlobals();
|
|
1345
|
+
const json = globalOptions.json ?? false;
|
|
1346
|
+
try {
|
|
1347
|
+
const spinner = ora8("Fetching MCPs...").start();
|
|
1348
|
+
const mcps = await api.get(
|
|
1349
|
+
"/api/mcp/repositories"
|
|
1350
|
+
);
|
|
1351
|
+
spinner.stop();
|
|
1352
|
+
const activeMcpId = await config.getMcpId();
|
|
1353
|
+
if (json) {
|
|
1354
|
+
formatOutput(
|
|
1355
|
+
{
|
|
1356
|
+
mcps: mcps.map((m) => ({
|
|
1357
|
+
...m,
|
|
1358
|
+
isActive: m.id === activeMcpId
|
|
1359
|
+
})),
|
|
1360
|
+
activeMcpId
|
|
1361
|
+
},
|
|
1362
|
+
true
|
|
1363
|
+
);
|
|
1364
|
+
} else {
|
|
1365
|
+
if (mcps.length === 0) {
|
|
1366
|
+
console.log("No MCPs found.");
|
|
1367
|
+
console.log("\nCreate a new MCP: waniwani mcp create <name>");
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
console.log(chalk6.bold("\nMCPs:\n"));
|
|
1371
|
+
const rows = mcps.map((m) => {
|
|
1372
|
+
const isActive = m.id === activeMcpId;
|
|
1373
|
+
const deployStatus = m.deployedAt ? chalk6.green("Deployed") : chalk6.yellow("Pending");
|
|
1374
|
+
const sandboxStatus = m.activeSandbox ? chalk6.green("Active") : chalk6.gray("None");
|
|
1375
|
+
const lastDeploy = m.deployedAt ? new Date(m.deployedAt).toLocaleDateString() : chalk6.gray("Never");
|
|
1376
|
+
return [
|
|
1377
|
+
isActive ? chalk6.cyan(`* ${m.name}`) : ` ${m.name}`,
|
|
1378
|
+
deployStatus,
|
|
1379
|
+
sandboxStatus,
|
|
1380
|
+
lastDeploy
|
|
1381
|
+
];
|
|
1382
|
+
});
|
|
1383
|
+
formatTable(["Name", "Status", "Sandbox", "Last Deploy"], rows, false);
|
|
1384
|
+
console.log();
|
|
1385
|
+
if (activeMcpId) {
|
|
1386
|
+
const activeMcp = mcps.find((m) => m.id === activeMcpId);
|
|
1387
|
+
if (activeMcp) {
|
|
1388
|
+
console.log(`Active MCP: ${chalk6.cyan(activeMcp.name)}`);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
console.log("\nSelect an MCP: waniwani mcp use <name>");
|
|
1118
1392
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
}
|
|
1123
|
-
if (existsSync3(join3(current, PROJECT_DIR))) {
|
|
1124
|
-
return current;
|
|
1125
|
-
}
|
|
1126
|
-
return null;
|
|
1127
|
-
}
|
|
1128
|
-
var DEFAULT_IGNORE_PATTERNS = [
|
|
1129
|
-
".waniwani",
|
|
1130
|
-
".git",
|
|
1131
|
-
"node_modules",
|
|
1132
|
-
".env",
|
|
1133
|
-
".env.*",
|
|
1134
|
-
".DS_Store",
|
|
1135
|
-
"*.log",
|
|
1136
|
-
".cache",
|
|
1137
|
-
"dist",
|
|
1138
|
-
"coverage",
|
|
1139
|
-
".turbo",
|
|
1140
|
-
".next",
|
|
1141
|
-
".nuxt",
|
|
1142
|
-
".vercel"
|
|
1143
|
-
];
|
|
1144
|
-
async function loadIgnorePatterns(projectRoot) {
|
|
1145
|
-
const ig = ignore();
|
|
1146
|
-
ig.add(DEFAULT_IGNORE_PATTERNS);
|
|
1147
|
-
const gitignorePath = join3(projectRoot, ".gitignore");
|
|
1148
|
-
if (existsSync3(gitignorePath)) {
|
|
1149
|
-
try {
|
|
1150
|
-
const content = await readFile3(gitignorePath, "utf-8");
|
|
1151
|
-
ig.add(content);
|
|
1152
|
-
} catch {
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
return ig;
|
|
1156
|
-
}
|
|
1157
|
-
async function collectFiles(projectRoot) {
|
|
1158
|
-
const ig = await loadIgnorePatterns(projectRoot);
|
|
1159
|
-
const files = [];
|
|
1160
|
-
async function walk(dir) {
|
|
1161
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
1162
|
-
for (const entry of entries) {
|
|
1163
|
-
const fullPath = join3(dir, entry.name);
|
|
1164
|
-
const relativePath = relative(projectRoot, fullPath);
|
|
1165
|
-
if (ig.ignores(relativePath)) {
|
|
1166
|
-
continue;
|
|
1167
|
-
}
|
|
1168
|
-
if (entry.isDirectory()) {
|
|
1169
|
-
await walk(fullPath);
|
|
1170
|
-
} else if (entry.isFile()) {
|
|
1171
|
-
try {
|
|
1172
|
-
const content = await readFile3(fullPath);
|
|
1173
|
-
const isBinary = isBinaryPath(fullPath) || detectBinary(content);
|
|
1174
|
-
files.push({
|
|
1175
|
-
path: relativePath,
|
|
1176
|
-
content: isBinary ? content.toString("base64") : content.toString("utf8"),
|
|
1177
|
-
encoding: isBinary ? "base64" : "utf8"
|
|
1178
|
-
});
|
|
1179
|
-
} catch {
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
await walk(projectRoot);
|
|
1185
|
-
return files;
|
|
1186
|
-
}
|
|
1187
|
-
async function pullFilesFromGithub(mcpId, targetDir) {
|
|
1188
|
-
const result = await api.get(
|
|
1189
|
-
`/api/mcp/repositories/${mcpId}/files`
|
|
1190
|
-
);
|
|
1191
|
-
const writtenFiles = [];
|
|
1192
|
-
for (const file of result.files) {
|
|
1193
|
-
const localPath = join3(targetDir, file.path);
|
|
1194
|
-
const dir = dirname(localPath);
|
|
1195
|
-
await mkdir2(dir, { recursive: true });
|
|
1196
|
-
if (file.encoding === "base64") {
|
|
1197
|
-
await writeFile3(localPath, Buffer.from(file.content, "base64"));
|
|
1198
|
-
} else {
|
|
1199
|
-
await writeFile3(localPath, file.content, "utf8");
|
|
1200
|
-
}
|
|
1201
|
-
writtenFiles.push(file.path);
|
|
1202
|
-
}
|
|
1203
|
-
return { count: writtenFiles.length, files: writtenFiles };
|
|
1204
|
-
}
|
|
1205
|
-
async function collectSingleFile(projectRoot, filePath) {
|
|
1206
|
-
const fullPath = join3(projectRoot, filePath);
|
|
1207
|
-
const relativePath = relative(projectRoot, fullPath);
|
|
1208
|
-
if (!existsSync3(fullPath)) {
|
|
1209
|
-
return null;
|
|
1210
|
-
}
|
|
1211
|
-
try {
|
|
1212
|
-
const fileStat = await stat(fullPath);
|
|
1213
|
-
if (!fileStat.isFile()) {
|
|
1214
|
-
return null;
|
|
1215
|
-
}
|
|
1216
|
-
const content = await readFile3(fullPath);
|
|
1217
|
-
const isBinary = isBinaryPath(fullPath) || detectBinary(content);
|
|
1218
|
-
return {
|
|
1219
|
-
path: relativePath,
|
|
1220
|
-
content: isBinary ? content.toString("base64") : content.toString("utf8"),
|
|
1221
|
-
encoding: isBinary ? "base64" : "utf8"
|
|
1222
|
-
};
|
|
1223
|
-
} catch {
|
|
1224
|
-
return null;
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
// src/commands/mcp/init.ts
|
|
1229
|
-
async function loadParentConfig(cwd) {
|
|
1230
|
-
const parentConfigPath = join4(cwd, LOCAL_CONFIG_DIR, CONFIG_FILE_NAME);
|
|
1231
|
-
if (!existsSync4(parentConfigPath)) {
|
|
1232
|
-
return null;
|
|
1233
|
-
}
|
|
1234
|
-
try {
|
|
1235
|
-
const content = await readFile4(parentConfigPath, "utf-8");
|
|
1236
|
-
const config2 = JSON.parse(content);
|
|
1237
|
-
const { mcpId: _, sessionId: __, ...rest } = config2;
|
|
1238
|
-
return rest;
|
|
1239
|
-
} catch {
|
|
1240
|
-
return null;
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
var initCommand = new Command10("init").description("Create a new MCP project").argument("<name>", "Name for the MCP project").action(async (name, _options, command) => {
|
|
1244
|
-
const globalOptions = command.optsWithGlobals();
|
|
1245
|
-
const json = globalOptions.json ?? false;
|
|
1246
|
-
try {
|
|
1247
|
-
const cwd = process.cwd();
|
|
1248
|
-
const projectDir = join4(cwd, name);
|
|
1249
|
-
if (existsSync4(projectDir)) {
|
|
1250
|
-
if (json) {
|
|
1251
|
-
formatOutput(
|
|
1252
|
-
{
|
|
1253
|
-
success: false,
|
|
1254
|
-
error: `Directory "${name}" already exists`
|
|
1255
|
-
},
|
|
1256
|
-
true
|
|
1257
|
-
);
|
|
1258
|
-
} else {
|
|
1259
|
-
console.error(`Error: Directory "${name}" already exists`);
|
|
1260
|
-
}
|
|
1261
|
-
process.exit(1);
|
|
1262
|
-
}
|
|
1263
|
-
const spinner = ora6("Creating MCP...").start();
|
|
1264
|
-
const result = await api.post("/api/mcp/repositories", {
|
|
1265
|
-
name
|
|
1266
|
-
});
|
|
1267
|
-
mkdirSync(projectDir, { recursive: true });
|
|
1268
|
-
const parentConfig = await loadParentConfig(cwd);
|
|
1269
|
-
await initConfigAt(projectDir, {
|
|
1270
|
-
...parentConfig,
|
|
1271
|
-
mcpId: result.id
|
|
1272
|
-
});
|
|
1273
|
-
spinner.succeed("MCP project created");
|
|
1274
|
-
spinner.start("Pulling template files...");
|
|
1275
|
-
const syncResult = await pullFilesFromGithub(result.id, projectDir);
|
|
1276
|
-
spinner.succeed(`Pulled ${syncResult.count} files`);
|
|
1277
|
-
if (json) {
|
|
1278
|
-
formatOutput(
|
|
1279
|
-
{
|
|
1280
|
-
success: true,
|
|
1281
|
-
projectDir,
|
|
1282
|
-
mcpId: result.id,
|
|
1283
|
-
files: syncResult.files
|
|
1284
|
-
},
|
|
1285
|
-
true
|
|
1286
|
-
);
|
|
1287
|
-
} else {
|
|
1288
|
-
console.log();
|
|
1289
|
-
formatSuccess(`MCP "${name}" created!`, false);
|
|
1290
|
-
console.log();
|
|
1291
|
-
console.log("Next steps:");
|
|
1292
|
-
console.log(` cd ${name}`);
|
|
1293
|
-
console.log(" waniwani mcp preview # Start developing");
|
|
1294
|
-
}
|
|
1295
|
-
} catch (error) {
|
|
1296
|
-
handleError(error, json);
|
|
1297
|
-
process.exit(1);
|
|
1298
|
-
}
|
|
1299
|
-
});
|
|
1300
|
-
|
|
1301
|
-
// src/commands/mcp/list.ts
|
|
1302
|
-
import chalk6 from "chalk";
|
|
1303
|
-
import { Command as Command11 } from "commander";
|
|
1304
|
-
import ora7 from "ora";
|
|
1305
|
-
var listCommand2 = new Command11("list").description("List all MCPs in your organization").action(async (_, command) => {
|
|
1306
|
-
const globalOptions = command.optsWithGlobals();
|
|
1307
|
-
const json = globalOptions.json ?? false;
|
|
1308
|
-
try {
|
|
1309
|
-
const spinner = ora7("Fetching MCPs...").start();
|
|
1310
|
-
const mcps = await api.get(
|
|
1311
|
-
"/api/mcp/repositories"
|
|
1312
|
-
);
|
|
1313
|
-
spinner.stop();
|
|
1314
|
-
const activeMcpId = await config.getMcpId();
|
|
1315
|
-
if (json) {
|
|
1316
|
-
formatOutput(
|
|
1317
|
-
{
|
|
1318
|
-
mcps: mcps.map((m) => ({
|
|
1319
|
-
...m,
|
|
1320
|
-
isActive: m.id === activeMcpId
|
|
1321
|
-
})),
|
|
1322
|
-
activeMcpId
|
|
1323
|
-
},
|
|
1324
|
-
true
|
|
1325
|
-
);
|
|
1326
|
-
} else {
|
|
1327
|
-
if (mcps.length === 0) {
|
|
1328
|
-
console.log("No MCPs found.");
|
|
1329
|
-
console.log("\nCreate a new MCP: waniwani mcp init <name>");
|
|
1330
|
-
return;
|
|
1331
|
-
}
|
|
1332
|
-
console.log(chalk6.bold("\nMCPs:\n"));
|
|
1333
|
-
const rows = mcps.map((m) => {
|
|
1334
|
-
const isActive = m.id === activeMcpId;
|
|
1335
|
-
const deployStatus = m.deployedAt ? chalk6.green("Deployed") : chalk6.yellow("Pending");
|
|
1336
|
-
const sandboxStatus = m.activeSandbox ? chalk6.green("Active") : chalk6.gray("None");
|
|
1337
|
-
const lastDeploy = m.deployedAt ? new Date(m.deployedAt).toLocaleDateString() : chalk6.gray("Never");
|
|
1338
|
-
return [
|
|
1339
|
-
isActive ? chalk6.cyan(`* ${m.name}`) : ` ${m.name}`,
|
|
1340
|
-
deployStatus,
|
|
1341
|
-
sandboxStatus,
|
|
1342
|
-
lastDeploy
|
|
1343
|
-
];
|
|
1344
|
-
});
|
|
1345
|
-
formatTable(["Name", "Status", "Sandbox", "Last Deploy"], rows, false);
|
|
1346
|
-
console.log();
|
|
1347
|
-
if (activeMcpId) {
|
|
1348
|
-
const activeMcp = mcps.find((m) => m.id === activeMcpId);
|
|
1349
|
-
if (activeMcp) {
|
|
1350
|
-
console.log(`Active MCP: ${chalk6.cyan(activeMcp.name)}`);
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
console.log("\nSelect an MCP: waniwani mcp use <name>");
|
|
1354
|
-
}
|
|
1355
|
-
} catch (error) {
|
|
1356
|
-
handleError(error, json);
|
|
1357
|
-
process.exit(1);
|
|
1393
|
+
} catch (error) {
|
|
1394
|
+
handleError(error, json);
|
|
1395
|
+
process.exit(1);
|
|
1358
1396
|
}
|
|
1359
1397
|
});
|
|
1360
1398
|
|
|
1361
1399
|
// src/commands/mcp/logs.ts
|
|
1362
1400
|
import chalk7 from "chalk";
|
|
1363
|
-
import { Command as
|
|
1364
|
-
import
|
|
1365
|
-
var logsCommand = new
|
|
1401
|
+
import { Command as Command13 } from "commander";
|
|
1402
|
+
import ora9 from "ora";
|
|
1403
|
+
var logsCommand = new Command13("logs").description("Stream logs from the MCP server").argument("[cmdId]", "Command ID (defaults to running server)").option("--mcp-id <id>", "Specific MCP ID").option("-f, --follow", "Keep streaming logs (default)", true).option("--no-follow", "Fetch logs and exit").action(async (cmdIdArg, options, command) => {
|
|
1366
1404
|
const globalOptions = command.optsWithGlobals();
|
|
1367
1405
|
const json = globalOptions.json ?? false;
|
|
1368
1406
|
let reader;
|
|
@@ -1386,7 +1424,7 @@ var logsCommand = new Command12("logs").description("Stream logs from the MCP se
|
|
|
1386
1424
|
}
|
|
1387
1425
|
let cmdId = cmdIdArg;
|
|
1388
1426
|
if (!cmdId) {
|
|
1389
|
-
const spinner =
|
|
1427
|
+
const spinner = ora9("Getting server status...").start();
|
|
1390
1428
|
const status = await api.post(
|
|
1391
1429
|
`/api/mcp/sessions/${sessionId}/server`,
|
|
1392
1430
|
{ action: "status" }
|
|
@@ -1503,16 +1541,140 @@ Error: ${event.error}`));
|
|
|
1503
1541
|
|
|
1504
1542
|
// src/commands/mcp/preview.ts
|
|
1505
1543
|
import { watch } from "chokidar";
|
|
1506
|
-
import { Command as
|
|
1507
|
-
import
|
|
1508
|
-
|
|
1544
|
+
import { Command as Command14 } from "commander";
|
|
1545
|
+
import ora10 from "ora";
|
|
1546
|
+
|
|
1547
|
+
// src/lib/sync.ts
|
|
1548
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1549
|
+
import { mkdir as mkdir2, readdir, readFile as readFile5, stat, writeFile as writeFile3 } from "fs/promises";
|
|
1550
|
+
import { dirname, join as join5, relative } from "path";
|
|
1551
|
+
import ignore from "ignore";
|
|
1552
|
+
var PROJECT_DIR = ".waniwani";
|
|
1553
|
+
async function findProjectRoot(startDir) {
|
|
1554
|
+
let current = startDir;
|
|
1555
|
+
const root = dirname(current);
|
|
1556
|
+
while (current !== root) {
|
|
1557
|
+
if (existsSync5(join5(current, PROJECT_DIR))) {
|
|
1558
|
+
return current;
|
|
1559
|
+
}
|
|
1560
|
+
const parent = dirname(current);
|
|
1561
|
+
if (parent === current) break;
|
|
1562
|
+
current = parent;
|
|
1563
|
+
}
|
|
1564
|
+
if (existsSync5(join5(current, PROJECT_DIR))) {
|
|
1565
|
+
return current;
|
|
1566
|
+
}
|
|
1567
|
+
return null;
|
|
1568
|
+
}
|
|
1569
|
+
var DEFAULT_IGNORE_PATTERNS = [
|
|
1570
|
+
".waniwani",
|
|
1571
|
+
".git",
|
|
1572
|
+
"node_modules",
|
|
1573
|
+
".env",
|
|
1574
|
+
".env.*",
|
|
1575
|
+
".DS_Store",
|
|
1576
|
+
"*.log",
|
|
1577
|
+
".cache",
|
|
1578
|
+
"dist",
|
|
1579
|
+
"coverage",
|
|
1580
|
+
".turbo",
|
|
1581
|
+
".next",
|
|
1582
|
+
".nuxt",
|
|
1583
|
+
".vercel"
|
|
1584
|
+
];
|
|
1585
|
+
async function loadIgnorePatterns(projectRoot) {
|
|
1586
|
+
const ig = ignore();
|
|
1587
|
+
ig.add(DEFAULT_IGNORE_PATTERNS);
|
|
1588
|
+
const gitignorePath = join5(projectRoot, ".gitignore");
|
|
1589
|
+
if (existsSync5(gitignorePath)) {
|
|
1590
|
+
try {
|
|
1591
|
+
const content = await readFile5(gitignorePath, "utf-8");
|
|
1592
|
+
ig.add(content);
|
|
1593
|
+
} catch {
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
return ig;
|
|
1597
|
+
}
|
|
1598
|
+
async function collectFiles(projectRoot) {
|
|
1599
|
+
const ig = await loadIgnorePatterns(projectRoot);
|
|
1600
|
+
const files = [];
|
|
1601
|
+
async function walk(dir) {
|
|
1602
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
1603
|
+
for (const entry of entries) {
|
|
1604
|
+
const fullPath = join5(dir, entry.name);
|
|
1605
|
+
const relativePath = relative(projectRoot, fullPath);
|
|
1606
|
+
if (ig.ignores(relativePath)) {
|
|
1607
|
+
continue;
|
|
1608
|
+
}
|
|
1609
|
+
if (entry.isDirectory()) {
|
|
1610
|
+
await walk(fullPath);
|
|
1611
|
+
} else if (entry.isFile()) {
|
|
1612
|
+
try {
|
|
1613
|
+
const content = await readFile5(fullPath);
|
|
1614
|
+
const isBinary = isBinaryPath(fullPath) || detectBinary(content);
|
|
1615
|
+
files.push({
|
|
1616
|
+
path: relativePath,
|
|
1617
|
+
content: isBinary ? content.toString("base64") : content.toString("utf8"),
|
|
1618
|
+
encoding: isBinary ? "base64" : "utf8"
|
|
1619
|
+
});
|
|
1620
|
+
} catch {
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
await walk(projectRoot);
|
|
1626
|
+
return files;
|
|
1627
|
+
}
|
|
1628
|
+
async function pullFilesFromGithub(mcpId, targetDir) {
|
|
1629
|
+
const result = await api.get(
|
|
1630
|
+
`/api/mcp/repositories/${mcpId}/files`
|
|
1631
|
+
);
|
|
1632
|
+
const writtenFiles = [];
|
|
1633
|
+
for (const file of result.files) {
|
|
1634
|
+
const localPath = join5(targetDir, file.path);
|
|
1635
|
+
const dir = dirname(localPath);
|
|
1636
|
+
await mkdir2(dir, { recursive: true });
|
|
1637
|
+
if (file.encoding === "base64") {
|
|
1638
|
+
await writeFile3(localPath, Buffer.from(file.content, "base64"));
|
|
1639
|
+
} else {
|
|
1640
|
+
await writeFile3(localPath, file.content, "utf8");
|
|
1641
|
+
}
|
|
1642
|
+
writtenFiles.push(file.path);
|
|
1643
|
+
}
|
|
1644
|
+
return { count: writtenFiles.length, files: writtenFiles };
|
|
1645
|
+
}
|
|
1646
|
+
async function collectSingleFile(projectRoot, filePath) {
|
|
1647
|
+
const fullPath = join5(projectRoot, filePath);
|
|
1648
|
+
const relativePath = relative(projectRoot, fullPath);
|
|
1649
|
+
if (!existsSync5(fullPath)) {
|
|
1650
|
+
return null;
|
|
1651
|
+
}
|
|
1652
|
+
try {
|
|
1653
|
+
const fileStat = await stat(fullPath);
|
|
1654
|
+
if (!fileStat.isFile()) {
|
|
1655
|
+
return null;
|
|
1656
|
+
}
|
|
1657
|
+
const content = await readFile5(fullPath);
|
|
1658
|
+
const isBinary = isBinaryPath(fullPath) || detectBinary(content);
|
|
1659
|
+
return {
|
|
1660
|
+
path: relativePath,
|
|
1661
|
+
content: isBinary ? content.toString("base64") : content.toString("utf8"),
|
|
1662
|
+
encoding: isBinary ? "base64" : "utf8"
|
|
1663
|
+
};
|
|
1664
|
+
} catch {
|
|
1665
|
+
return null;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
// src/commands/mcp/preview.ts
|
|
1670
|
+
var previewCommand = new Command14("preview").description("Start live development with sandbox and file watching").option("--mcp-id <id>", "Specific MCP ID").option("--no-watch", "Skip file watching").option("--no-logs", "Don't stream logs to terminal").action(async (options, command) => {
|
|
1509
1671
|
const globalOptions = command.optsWithGlobals();
|
|
1510
1672
|
const json = globalOptions.json ?? false;
|
|
1511
1673
|
try {
|
|
1512
1674
|
const projectRoot = await findProjectRoot(process.cwd());
|
|
1513
1675
|
if (!projectRoot) {
|
|
1514
1676
|
throw new CLIError(
|
|
1515
|
-
"Not in a WaniWani project. Run 'waniwani mcp
|
|
1677
|
+
"Not in a WaniWani project. Run 'waniwani mcp create <name>' first.",
|
|
1516
1678
|
"NOT_IN_PROJECT"
|
|
1517
1679
|
);
|
|
1518
1680
|
}
|
|
@@ -1522,11 +1684,11 @@ var previewCommand = new Command13("preview").description("Start live developmen
|
|
|
1522
1684
|
}
|
|
1523
1685
|
if (!mcpId) {
|
|
1524
1686
|
throw new CLIError(
|
|
1525
|
-
"No MCP found. Run 'waniwani mcp
|
|
1687
|
+
"No MCP found. Run 'waniwani mcp create <name>' or use --mcp-id.",
|
|
1526
1688
|
"NO_MCP"
|
|
1527
1689
|
);
|
|
1528
1690
|
}
|
|
1529
|
-
const spinner =
|
|
1691
|
+
const spinner = ora10("Starting development environment...").start();
|
|
1530
1692
|
spinner.text = "Starting session...";
|
|
1531
1693
|
let sessionId;
|
|
1532
1694
|
let previewUrl;
|
|
@@ -1621,10 +1783,11 @@ var previewCommand = new Command13("preview").description("Start live developmen
|
|
|
1621
1783
|
});
|
|
1622
1784
|
|
|
1623
1785
|
// src/commands/mcp/publish.ts
|
|
1786
|
+
import { execSync as execSync3 } from "child_process";
|
|
1624
1787
|
import { input } from "@inquirer/prompts";
|
|
1625
|
-
import { Command as
|
|
1626
|
-
import
|
|
1627
|
-
var publishCommand = new
|
|
1788
|
+
import { Command as Command15 } from "commander";
|
|
1789
|
+
import ora11 from "ora";
|
|
1790
|
+
var publishCommand = new Command15("publish").description("Push local files to GitHub and trigger deployment").option("-m, --message <msg>", "Commit message").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1628
1791
|
const globalOptions = command.optsWithGlobals();
|
|
1629
1792
|
const json = globalOptions.json ?? false;
|
|
1630
1793
|
try {
|
|
@@ -1632,10 +1795,33 @@ var publishCommand = new Command14("publish").description("Push local files to G
|
|
|
1632
1795
|
const projectRoot = await findProjectRoot(process.cwd());
|
|
1633
1796
|
if (!projectRoot) {
|
|
1634
1797
|
throw new CLIError(
|
|
1635
|
-
"Not in a WaniWani project. Run 'waniwani mcp
|
|
1798
|
+
"Not in a WaniWani project. Run 'waniwani mcp create <name>' first.",
|
|
1636
1799
|
"NOT_IN_PROJECT"
|
|
1637
1800
|
);
|
|
1638
1801
|
}
|
|
1802
|
+
try {
|
|
1803
|
+
execSync3("git rev-parse --is-inside-work-tree", {
|
|
1804
|
+
cwd: projectRoot,
|
|
1805
|
+
stdio: "ignore"
|
|
1806
|
+
});
|
|
1807
|
+
} catch {
|
|
1808
|
+
throw new CLIError(
|
|
1809
|
+
"Not a git repository. Run 'waniwani mcp create <name>' or 'waniwani mcp clone <name>' to set up properly.",
|
|
1810
|
+
"NOT_GIT_REPO"
|
|
1811
|
+
);
|
|
1812
|
+
}
|
|
1813
|
+
const status = execSync3("git status --porcelain", {
|
|
1814
|
+
cwd: projectRoot,
|
|
1815
|
+
encoding: "utf-8"
|
|
1816
|
+
}).trim();
|
|
1817
|
+
if (!status) {
|
|
1818
|
+
if (json) {
|
|
1819
|
+
formatOutput({ success: true, message: "Nothing to publish" }, true);
|
|
1820
|
+
} else {
|
|
1821
|
+
console.log("Nothing to publish \u2014 no changes detected.");
|
|
1822
|
+
}
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1639
1825
|
let message = options.message;
|
|
1640
1826
|
if (!message) {
|
|
1641
1827
|
message = await input({
|
|
@@ -1643,20 +1829,43 @@ var publishCommand = new Command14("publish").description("Push local files to G
|
|
|
1643
1829
|
validate: (value) => value.trim() ? true : "Commit message is required"
|
|
1644
1830
|
});
|
|
1645
1831
|
}
|
|
1646
|
-
const spinner =
|
|
1647
|
-
const
|
|
1648
|
-
|
|
1649
|
-
spinner.fail("No files to deploy");
|
|
1650
|
-
return;
|
|
1651
|
-
}
|
|
1652
|
-
spinner.text = `Pushing ${files.length} files to GitHub...`;
|
|
1653
|
-
const result = await api.post(
|
|
1654
|
-
`/api/mcp/repositories/${mcpId}/deploy`,
|
|
1655
|
-
{ files, message }
|
|
1832
|
+
const spinner = ora11("Publishing...").start();
|
|
1833
|
+
const { cloneUrl } = await api.get(
|
|
1834
|
+
`/api/mcp/repositories/${mcpId}/clone-url`
|
|
1656
1835
|
);
|
|
1657
|
-
spinner.
|
|
1836
|
+
spinner.text = "Committing changes...";
|
|
1837
|
+
execSync3("git add -A", { cwd: projectRoot, stdio: "ignore" });
|
|
1838
|
+
execSync3(`git commit -m "${message.replace(/"/g, '\\"')}"`, {
|
|
1839
|
+
cwd: projectRoot,
|
|
1840
|
+
stdio: "ignore"
|
|
1841
|
+
});
|
|
1842
|
+
spinner.text = "Pushing to GitHub...";
|
|
1843
|
+
const originalUrl = execSync3("git remote get-url origin", {
|
|
1844
|
+
cwd: projectRoot,
|
|
1845
|
+
encoding: "utf-8"
|
|
1846
|
+
}).trim();
|
|
1847
|
+
try {
|
|
1848
|
+
execSync3(`git remote set-url origin "${cloneUrl}"`, {
|
|
1849
|
+
cwd: projectRoot,
|
|
1850
|
+
stdio: "ignore"
|
|
1851
|
+
});
|
|
1852
|
+
execSync3("git push origin HEAD", {
|
|
1853
|
+
cwd: projectRoot,
|
|
1854
|
+
stdio: "ignore"
|
|
1855
|
+
});
|
|
1856
|
+
} finally {
|
|
1857
|
+
execSync3(`git remote set-url origin "${originalUrl}"`, {
|
|
1858
|
+
cwd: projectRoot,
|
|
1859
|
+
stdio: "ignore"
|
|
1860
|
+
});
|
|
1861
|
+
}
|
|
1862
|
+
const commitSha = execSync3("git rev-parse HEAD", {
|
|
1863
|
+
cwd: projectRoot,
|
|
1864
|
+
encoding: "utf-8"
|
|
1865
|
+
}).trim();
|
|
1866
|
+
spinner.succeed(`Pushed to GitHub (${commitSha.slice(0, 7)})`);
|
|
1658
1867
|
if (json) {
|
|
1659
|
-
formatOutput(
|
|
1868
|
+
formatOutput({ commitSha, message }, true);
|
|
1660
1869
|
} else {
|
|
1661
1870
|
console.log();
|
|
1662
1871
|
formatSuccess("Files pushed to GitHub!", false);
|
|
@@ -1671,9 +1880,9 @@ var publishCommand = new Command14("publish").description("Push local files to G
|
|
|
1671
1880
|
|
|
1672
1881
|
// src/commands/mcp/run-command.ts
|
|
1673
1882
|
import chalk8 from "chalk";
|
|
1674
|
-
import { Command as
|
|
1675
|
-
import
|
|
1676
|
-
var runCommandCommand = new
|
|
1883
|
+
import { Command as Command16 } from "commander";
|
|
1884
|
+
import ora12 from "ora";
|
|
1885
|
+
var runCommandCommand = new Command16("run-command").description("Run a command in the MCP sandbox").argument("<command>", "Command to run").argument("[args...]", "Command arguments").option("--mcp-id <id>", "Specific MCP ID").option("--cwd <path>", "Working directory").option(
|
|
1677
1886
|
"--timeout <ms>",
|
|
1678
1887
|
"Command timeout in milliseconds (default: 30000, max: 300000)"
|
|
1679
1888
|
).action(async (cmd, args, options, command) => {
|
|
@@ -1683,7 +1892,7 @@ var runCommandCommand = new Command15("run-command").description("Run a command
|
|
|
1683
1892
|
await requireMcpId(options.mcpId);
|
|
1684
1893
|
const sessionId = await requireSessionId();
|
|
1685
1894
|
const timeout = options.timeout ? Number.parseInt(options.timeout, 10) : void 0;
|
|
1686
|
-
const spinner =
|
|
1895
|
+
const spinner = ora12(`Running: ${cmd} ${args.join(" ")}`.trim()).start();
|
|
1687
1896
|
const result = await api.post(
|
|
1688
1897
|
`/api/mcp/sessions/${sessionId}/commands`,
|
|
1689
1898
|
{
|
|
@@ -1730,14 +1939,14 @@ var runCommandCommand = new Command15("run-command").description("Run a command
|
|
|
1730
1939
|
|
|
1731
1940
|
// src/commands/mcp/status.ts
|
|
1732
1941
|
import chalk9 from "chalk";
|
|
1733
|
-
import { Command as
|
|
1734
|
-
import
|
|
1735
|
-
var statusCommand = new
|
|
1942
|
+
import { Command as Command17 } from "commander";
|
|
1943
|
+
import ora13 from "ora";
|
|
1944
|
+
var statusCommand = new Command17("status").description("Show current MCP status").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1736
1945
|
const globalOptions = command.optsWithGlobals();
|
|
1737
1946
|
const json = globalOptions.json ?? false;
|
|
1738
1947
|
try {
|
|
1739
1948
|
const mcpId = await requireMcpId(options.mcpId);
|
|
1740
|
-
const spinner =
|
|
1949
|
+
const spinner = ora13("Fetching MCP status...").start();
|
|
1741
1950
|
const result = await api.get(
|
|
1742
1951
|
`/api/mcp/repositories/${mcpId}`
|
|
1743
1952
|
);
|
|
@@ -1806,15 +2015,15 @@ var statusCommand = new Command16("status").description("Show current MCP status
|
|
|
1806
2015
|
});
|
|
1807
2016
|
|
|
1808
2017
|
// src/commands/mcp/stop.ts
|
|
1809
|
-
import { Command as
|
|
1810
|
-
import
|
|
1811
|
-
var stopCommand = new
|
|
2018
|
+
import { Command as Command18 } from "commander";
|
|
2019
|
+
import ora14 from "ora";
|
|
2020
|
+
var stopCommand = new Command18("stop").description("Stop the development environment (sandbox + server)").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1812
2021
|
const globalOptions = command.optsWithGlobals();
|
|
1813
2022
|
const json = globalOptions.json ?? false;
|
|
1814
2023
|
try {
|
|
1815
2024
|
await requireMcpId(options.mcpId);
|
|
1816
2025
|
const sessionId = await requireSessionId();
|
|
1817
|
-
const spinner =
|
|
2026
|
+
const spinner = ora14("Stopping development environment...").start();
|
|
1818
2027
|
try {
|
|
1819
2028
|
await api.post(`/api/mcp/sessions/${sessionId}/server`, {
|
|
1820
2029
|
action: "stop"
|
|
@@ -1838,9 +2047,9 @@ var stopCommand = new Command17("stop").description("Stop the development enviro
|
|
|
1838
2047
|
});
|
|
1839
2048
|
|
|
1840
2049
|
// src/commands/mcp/sync.ts
|
|
1841
|
-
import { Command as
|
|
1842
|
-
import
|
|
1843
|
-
var syncCommand = new
|
|
2050
|
+
import { Command as Command19 } from "commander";
|
|
2051
|
+
import ora15 from "ora";
|
|
2052
|
+
var syncCommand = new Command19("sync").description("Pull template files to local project").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1844
2053
|
const globalOptions = command.optsWithGlobals();
|
|
1845
2054
|
const json = globalOptions.json ?? false;
|
|
1846
2055
|
try {
|
|
@@ -1848,11 +2057,11 @@ var syncCommand = new Command18("sync").description("Pull template files to loca
|
|
|
1848
2057
|
const projectRoot = await findProjectRoot(process.cwd());
|
|
1849
2058
|
if (!projectRoot) {
|
|
1850
2059
|
throw new CLIError(
|
|
1851
|
-
"Not in a WaniWani project. Run 'waniwani mcp
|
|
2060
|
+
"Not in a WaniWani project. Run 'waniwani mcp create <name>' first.",
|
|
1852
2061
|
"NOT_IN_PROJECT"
|
|
1853
2062
|
);
|
|
1854
2063
|
}
|
|
1855
|
-
const spinner =
|
|
2064
|
+
const spinner = ora15("Pulling files...").start();
|
|
1856
2065
|
const result = await pullFilesFromGithub(mcpId, projectRoot);
|
|
1857
2066
|
spinner.succeed(`Pulled ${result.count} files`);
|
|
1858
2067
|
if (json) {
|
|
@@ -1874,13 +2083,13 @@ var syncCommand = new Command18("sync").description("Pull template files to loca
|
|
|
1874
2083
|
});
|
|
1875
2084
|
|
|
1876
2085
|
// src/commands/mcp/use.ts
|
|
1877
|
-
import { Command as
|
|
1878
|
-
import
|
|
1879
|
-
var useCommand = new
|
|
2086
|
+
import { Command as Command20 } from "commander";
|
|
2087
|
+
import ora16 from "ora";
|
|
2088
|
+
var useCommand = new Command20("use").description("Select an MCP to use for subsequent commands").argument("<name>", "Name of the MCP to use").action(async (name, _options, command) => {
|
|
1880
2089
|
const globalOptions = command.optsWithGlobals();
|
|
1881
2090
|
const json = globalOptions.json ?? false;
|
|
1882
2091
|
try {
|
|
1883
|
-
const spinner =
|
|
2092
|
+
const spinner = ora16("Fetching MCPs...").start();
|
|
1884
2093
|
const mcps = await api.get(
|
|
1885
2094
|
"/api/mcp/repositories"
|
|
1886
2095
|
);
|
|
@@ -1911,20 +2120,20 @@ var useCommand = new Command19("use").description("Select an MCP to use for subs
|
|
|
1911
2120
|
});
|
|
1912
2121
|
|
|
1913
2122
|
// src/commands/mcp/index.ts
|
|
1914
|
-
var mcpCommand = new
|
|
2123
|
+
var mcpCommand = new Command21("mcp").description("MCP management commands").addCommand(createCommand).addCommand(cloneCommand).addCommand(listCommand2).addCommand(useCommand).addCommand(statusCommand).addCommand(previewCommand).addCommand(stopCommand).addCommand(logsCommand).addCommand(syncCommand).addCommand(publishCommand).addCommand(deleteCommand).addCommand(fileCommand).addCommand(runCommandCommand);
|
|
1915
2124
|
|
|
1916
2125
|
// src/commands/org/index.ts
|
|
1917
|
-
import { Command as
|
|
2126
|
+
import { Command as Command24 } from "commander";
|
|
1918
2127
|
|
|
1919
2128
|
// src/commands/org/list.ts
|
|
1920
2129
|
import chalk10 from "chalk";
|
|
1921
|
-
import { Command as
|
|
1922
|
-
import
|
|
1923
|
-
var listCommand3 = new
|
|
2130
|
+
import { Command as Command22 } from "commander";
|
|
2131
|
+
import ora17 from "ora";
|
|
2132
|
+
var listCommand3 = new Command22("list").description("List your organizations").action(async (_, command) => {
|
|
1924
2133
|
const globalOptions = command.optsWithGlobals();
|
|
1925
2134
|
const json = globalOptions.json ?? false;
|
|
1926
2135
|
try {
|
|
1927
|
-
const spinner =
|
|
2136
|
+
const spinner = ora17("Fetching organizations...").start();
|
|
1928
2137
|
const result = await api.get("/api/oauth/orgs");
|
|
1929
2138
|
spinner.stop();
|
|
1930
2139
|
const { orgs, activeOrgId } = result;
|
|
@@ -1970,13 +2179,13 @@ var listCommand3 = new Command21("list").description("List your organizations").
|
|
|
1970
2179
|
});
|
|
1971
2180
|
|
|
1972
2181
|
// src/commands/org/switch.ts
|
|
1973
|
-
import { Command as
|
|
1974
|
-
import
|
|
1975
|
-
var switchCommand = new
|
|
2182
|
+
import { Command as Command23 } from "commander";
|
|
2183
|
+
import ora18 from "ora";
|
|
2184
|
+
var switchCommand = new Command23("switch").description("Switch to a different organization").argument("<name>", "Name or slug of the organization to switch to").action(async (name, _, command) => {
|
|
1976
2185
|
const globalOptions = command.optsWithGlobals();
|
|
1977
2186
|
const json = globalOptions.json ?? false;
|
|
1978
2187
|
try {
|
|
1979
|
-
const spinner =
|
|
2188
|
+
const spinner = ora18("Fetching organizations...").start();
|
|
1980
2189
|
const { orgs } = await api.get("/api/oauth/orgs");
|
|
1981
2190
|
const org = orgs.find((o) => o.name === name || o.slug === name);
|
|
1982
2191
|
if (!org) {
|
|
@@ -2009,12 +2218,12 @@ var switchCommand = new Command22("switch").description("Switch to a different o
|
|
|
2009
2218
|
});
|
|
2010
2219
|
|
|
2011
2220
|
// src/commands/org/index.ts
|
|
2012
|
-
var orgCommand = new
|
|
2221
|
+
var orgCommand = new Command24("org").description("Organization management commands").addCommand(listCommand3).addCommand(switchCommand);
|
|
2013
2222
|
|
|
2014
2223
|
// src/cli.ts
|
|
2015
2224
|
var require2 = createRequire(import.meta.url);
|
|
2016
2225
|
var { version } = require2("../package.json");
|
|
2017
|
-
var program = new
|
|
2226
|
+
var program = new Command25().name("waniwani").description("WaniWani CLI for MCP development workflow").version(version).option("--json", "Output results as JSON").option("--verbose", "Enable verbose logging");
|
|
2018
2227
|
program.addCommand(loginCommand);
|
|
2019
2228
|
program.addCommand(logoutCommand);
|
|
2020
2229
|
program.addCommand(mcpCommand);
|