@waniwani/cli 0.0.34 → 0.0.35
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 +134 -148
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14,33 +14,31 @@ import { Command } from "commander";
|
|
|
14
14
|
// src/lib/config.ts
|
|
15
15
|
import { existsSync } from "fs";
|
|
16
16
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
17
|
-
import { homedir } from "os";
|
|
18
17
|
import { join } from "path";
|
|
19
18
|
import { z } from "zod";
|
|
20
19
|
var LOCAL_CONFIG_DIR = ".waniwani";
|
|
21
20
|
var CONFIG_FILE_NAME = "settings.json";
|
|
22
21
|
var LOCAL_DIR = join(process.cwd(), LOCAL_CONFIG_DIR);
|
|
23
22
|
var LOCAL_FILE = join(LOCAL_DIR, CONFIG_FILE_NAME);
|
|
24
|
-
var GLOBAL_DIR = join(homedir(), LOCAL_CONFIG_DIR);
|
|
25
|
-
var GLOBAL_FILE = join(GLOBAL_DIR, CONFIG_FILE_NAME);
|
|
26
23
|
var DEFAULT_API_URL = "https://app.waniwani.ai";
|
|
27
24
|
var ConfigSchema = z.object({
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
// Settings
|
|
26
|
+
sessionId: z.string().nullable().default(null),
|
|
27
|
+
mcpId: z.string().nullable().default(null),
|
|
28
|
+
apiUrl: z.string().default(DEFAULT_API_URL),
|
|
29
|
+
// Auth (merged from auth.json)
|
|
30
|
+
accessToken: z.string().nullable().default(null),
|
|
31
|
+
refreshToken: z.string().nullable().default(null),
|
|
32
|
+
expiresAt: z.string().nullable().default(null),
|
|
33
|
+
clientId: z.string().nullable().default(null)
|
|
33
34
|
});
|
|
34
35
|
var Config = class {
|
|
35
36
|
dir;
|
|
36
37
|
file;
|
|
37
38
|
cache = null;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.dir = useLocal ? LOCAL_DIR : GLOBAL_DIR;
|
|
42
|
-
this.file = useLocal ? LOCAL_FILE : GLOBAL_FILE;
|
|
43
|
-
this.scope = useLocal ? "local" : "global";
|
|
39
|
+
constructor() {
|
|
40
|
+
this.dir = LOCAL_DIR;
|
|
41
|
+
this.file = LOCAL_FILE;
|
|
44
42
|
}
|
|
45
43
|
async load() {
|
|
46
44
|
if (!this.cache) {
|
|
@@ -59,12 +57,34 @@ var Config = class {
|
|
|
59
57
|
await mkdir(this.dir, { recursive: true });
|
|
60
58
|
await writeFile(this.file, JSON.stringify(data, null, " "));
|
|
61
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Ensure the .waniwani directory exists in cwd.
|
|
62
|
+
* Used by login to create config before saving tokens.
|
|
63
|
+
*/
|
|
64
|
+
async ensureConfigDir() {
|
|
65
|
+
await mkdir(this.dir, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if a .waniwani config directory exists in cwd.
|
|
69
|
+
*/
|
|
70
|
+
hasConfig() {
|
|
71
|
+
return existsSync(this.dir);
|
|
72
|
+
}
|
|
73
|
+
// --- Settings methods ---
|
|
62
74
|
async getMcpId() {
|
|
63
|
-
return (await this.load()).
|
|
75
|
+
return (await this.load()).mcpId;
|
|
64
76
|
}
|
|
65
77
|
async setMcpId(id) {
|
|
66
78
|
const data = await this.load();
|
|
67
|
-
data.
|
|
79
|
+
data.mcpId = id;
|
|
80
|
+
await this.save(data);
|
|
81
|
+
}
|
|
82
|
+
async getSessionId() {
|
|
83
|
+
return (await this.load()).sessionId;
|
|
84
|
+
}
|
|
85
|
+
async setSessionId(id) {
|
|
86
|
+
const data = await this.load();
|
|
87
|
+
data.sessionId = id;
|
|
68
88
|
await this.save(data);
|
|
69
89
|
}
|
|
70
90
|
async getApiUrl() {
|
|
@@ -74,9 +94,42 @@ var Config = class {
|
|
|
74
94
|
async clear() {
|
|
75
95
|
await this.save(ConfigSchema.parse({}));
|
|
76
96
|
}
|
|
97
|
+
// --- Auth methods ---
|
|
98
|
+
async getAccessToken() {
|
|
99
|
+
return (await this.load()).accessToken;
|
|
100
|
+
}
|
|
101
|
+
async getRefreshToken() {
|
|
102
|
+
return (await this.load()).refreshToken;
|
|
103
|
+
}
|
|
104
|
+
async getClientId() {
|
|
105
|
+
return (await this.load()).clientId;
|
|
106
|
+
}
|
|
107
|
+
async setTokens(accessToken, refreshToken, expiresIn, clientId) {
|
|
108
|
+
const expiresAt = new Date(Date.now() + expiresIn * 1e3).toISOString();
|
|
109
|
+
const data = await this.load();
|
|
110
|
+
data.accessToken = accessToken;
|
|
111
|
+
data.refreshToken = refreshToken;
|
|
112
|
+
data.expiresAt = expiresAt;
|
|
113
|
+
if (clientId) {
|
|
114
|
+
data.clientId = clientId;
|
|
115
|
+
}
|
|
116
|
+
await this.save(data);
|
|
117
|
+
}
|
|
118
|
+
async clearAuth() {
|
|
119
|
+
const data = await this.load();
|
|
120
|
+
data.accessToken = null;
|
|
121
|
+
data.refreshToken = null;
|
|
122
|
+
data.expiresAt = null;
|
|
123
|
+
data.clientId = null;
|
|
124
|
+
await this.save(data);
|
|
125
|
+
}
|
|
126
|
+
async isTokenExpired() {
|
|
127
|
+
const data = await this.load();
|
|
128
|
+
if (!data.expiresAt) return true;
|
|
129
|
+
return new Date(data.expiresAt).getTime() - 5 * 60 * 1e3 < Date.now();
|
|
130
|
+
}
|
|
77
131
|
};
|
|
78
132
|
var config = new Config();
|
|
79
|
-
var globalConfig = new Config(true);
|
|
80
133
|
async function initConfigAt(dir, overrides = {}) {
|
|
81
134
|
const configDir = join(dir, LOCAL_CONFIG_DIR);
|
|
82
135
|
const configPath = join(configDir, CONFIG_FILE_NAME);
|
|
@@ -241,82 +294,29 @@ import { Command as Command3 } from "commander";
|
|
|
241
294
|
import ora from "ora";
|
|
242
295
|
|
|
243
296
|
// src/lib/auth.ts
|
|
244
|
-
import { access, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
245
|
-
import { homedir as homedir2 } from "os";
|
|
246
|
-
import { join as join3 } from "path";
|
|
247
|
-
import { z as z2 } from "zod";
|
|
248
|
-
var CONFIG_DIR = join3(homedir2(), ".waniwani");
|
|
249
|
-
var AUTH_FILE = join3(CONFIG_DIR, "auth.json");
|
|
250
|
-
var AuthStoreSchema = z2.object({
|
|
251
|
-
accessToken: z2.string().nullable().default(null),
|
|
252
|
-
refreshToken: z2.string().nullable().default(null),
|
|
253
|
-
expiresAt: z2.string().nullable().default(null),
|
|
254
|
-
clientId: z2.string().nullable().default(null)
|
|
255
|
-
});
|
|
256
|
-
async function ensureConfigDir() {
|
|
257
|
-
await mkdir2(CONFIG_DIR, { recursive: true });
|
|
258
|
-
}
|
|
259
|
-
async function readAuthStore() {
|
|
260
|
-
await ensureConfigDir();
|
|
261
|
-
try {
|
|
262
|
-
await access(AUTH_FILE);
|
|
263
|
-
const content = await readFile2(AUTH_FILE, "utf-8");
|
|
264
|
-
return AuthStoreSchema.parse(JSON.parse(content));
|
|
265
|
-
} catch {
|
|
266
|
-
return AuthStoreSchema.parse({});
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
async function writeAuthStore(store) {
|
|
270
|
-
await ensureConfigDir();
|
|
271
|
-
await writeFile2(AUTH_FILE, JSON.stringify(store, null, 2), "utf-8");
|
|
272
|
-
}
|
|
273
297
|
var AuthManager = class {
|
|
274
|
-
storeCache = null;
|
|
275
|
-
async getStore() {
|
|
276
|
-
if (!this.storeCache) {
|
|
277
|
-
this.storeCache = await readAuthStore();
|
|
278
|
-
}
|
|
279
|
-
return this.storeCache;
|
|
280
|
-
}
|
|
281
|
-
async saveStore(store) {
|
|
282
|
-
this.storeCache = store;
|
|
283
|
-
await writeAuthStore(store);
|
|
284
|
-
}
|
|
285
298
|
async isLoggedIn() {
|
|
286
|
-
const
|
|
287
|
-
return !!
|
|
299
|
+
const token = await config.getAccessToken();
|
|
300
|
+
return !!token;
|
|
288
301
|
}
|
|
289
302
|
async getAccessToken() {
|
|
290
|
-
|
|
291
|
-
return store.accessToken;
|
|
303
|
+
return config.getAccessToken();
|
|
292
304
|
}
|
|
293
305
|
async getRefreshToken() {
|
|
294
|
-
|
|
295
|
-
return store.refreshToken;
|
|
306
|
+
return config.getRefreshToken();
|
|
296
307
|
}
|
|
297
308
|
async setTokens(accessToken, refreshToken, expiresIn, clientId) {
|
|
298
|
-
|
|
299
|
-
const store = await this.getStore();
|
|
300
|
-
store.accessToken = accessToken;
|
|
301
|
-
store.refreshToken = refreshToken;
|
|
302
|
-
store.expiresAt = expiresAt;
|
|
303
|
-
if (clientId) {
|
|
304
|
-
store.clientId = clientId;
|
|
305
|
-
}
|
|
306
|
-
await this.saveStore(store);
|
|
309
|
+
return config.setTokens(accessToken, refreshToken, expiresIn, clientId);
|
|
307
310
|
}
|
|
308
311
|
async clear() {
|
|
309
|
-
|
|
310
|
-
await this.saveStore(emptyStore);
|
|
312
|
+
return config.clearAuth();
|
|
311
313
|
}
|
|
312
314
|
async isTokenExpired() {
|
|
313
|
-
|
|
314
|
-
if (!store.expiresAt) return true;
|
|
315
|
-
return new Date(store.expiresAt).getTime() - 5 * 60 * 1e3 < Date.now();
|
|
315
|
+
return config.isTokenExpired();
|
|
316
316
|
}
|
|
317
317
|
async tryRefreshToken() {
|
|
318
|
-
const
|
|
319
|
-
const
|
|
318
|
+
const refreshToken = await config.getRefreshToken();
|
|
319
|
+
const clientId = await config.getClientId();
|
|
320
320
|
if (!refreshToken || !clientId) return false;
|
|
321
321
|
try {
|
|
322
322
|
const apiUrl = await config.getApiUrl();
|
|
@@ -468,7 +468,10 @@ async function waitForCallback(expectedState, timeoutMs = 3e5) {
|
|
|
468
468
|
text-align: center;
|
|
469
469
|
}
|
|
470
470
|
.logo {
|
|
471
|
-
|
|
471
|
+
font-size: 1.75rem;
|
|
472
|
+
font-weight: 700;
|
|
473
|
+
color: #1e293b;
|
|
474
|
+
letter-spacing: -0.025em;
|
|
472
475
|
}
|
|
473
476
|
.icon-circle {
|
|
474
477
|
width: 80px;
|
|
@@ -501,9 +504,7 @@ async function waitForCallback(expectedState, timeoutMs = 3e5) {
|
|
|
501
504
|
<div class="blob blob-2"></div>
|
|
502
505
|
<div class="blob blob-3"></div>
|
|
503
506
|
<div class="container">
|
|
504
|
-
<
|
|
505
|
-
<text x="0" y="32" font-family="system-ui" font-size="28" font-weight="bold" fill="#1e293b">WaniWani</text>
|
|
506
|
-
</svg>
|
|
507
|
+
<span class="logo">WaniWani</span>
|
|
507
508
|
<div class="icon-circle">
|
|
508
509
|
${isSuccess ? '<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"></path></svg>' : '<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg>'}
|
|
509
510
|
</div>
|
|
@@ -699,6 +700,7 @@ var loginCommand = new Command3("login").description("Log in to WaniWani").optio
|
|
|
699
700
|
apiUrl
|
|
700
701
|
// RFC 8707 resource parameter
|
|
701
702
|
);
|
|
703
|
+
await config.ensureConfigDir();
|
|
702
704
|
await auth.setTokens(
|
|
703
705
|
tokenResponse.access_token,
|
|
704
706
|
tokenResponse.refresh_token,
|
|
@@ -861,16 +863,14 @@ async function requireMcpId(mcpId) {
|
|
|
861
863
|
}
|
|
862
864
|
return configMcpId;
|
|
863
865
|
}
|
|
864
|
-
async function requireSessionId(
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
);
|
|
868
|
-
if (!repository.activeSandbox) {
|
|
866
|
+
async function requireSessionId() {
|
|
867
|
+
const sessionId = await config.getSessionId();
|
|
868
|
+
if (!sessionId) {
|
|
869
869
|
throw new McpError(
|
|
870
870
|
"No active session. Run 'waniwani mcp dev' to start development."
|
|
871
871
|
);
|
|
872
872
|
}
|
|
873
|
-
return
|
|
873
|
+
return sessionId;
|
|
874
874
|
}
|
|
875
875
|
var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
876
876
|
".png",
|
|
@@ -940,6 +940,7 @@ var deleteCommand = new Command5("delete").description("Delete the MCP (includes
|
|
|
940
940
|
spinner.succeed("MCP deleted");
|
|
941
941
|
if (await config.getMcpId() === mcpId) {
|
|
942
942
|
await config.setMcpId(null);
|
|
943
|
+
await config.setSessionId(null);
|
|
943
944
|
}
|
|
944
945
|
if (json) {
|
|
945
946
|
formatOutput({ deleted: mcpId }, true);
|
|
@@ -959,37 +960,26 @@ import ora3 from "ora";
|
|
|
959
960
|
|
|
960
961
|
// src/lib/sync.ts
|
|
961
962
|
import { existsSync as existsSync3 } from "fs";
|
|
962
|
-
import { mkdir as
|
|
963
|
-
import { dirname, join as
|
|
963
|
+
import { mkdir as mkdir2, readdir, readFile as readFile2, stat, writeFile as writeFile2 } from "fs/promises";
|
|
964
|
+
import { dirname, join as join3, relative } from "path";
|
|
964
965
|
import ignore from "ignore";
|
|
965
966
|
var PROJECT_DIR = ".waniwani";
|
|
966
|
-
var SETTINGS_FILE = "settings.json";
|
|
967
967
|
async function findProjectRoot(startDir) {
|
|
968
968
|
let current = startDir;
|
|
969
969
|
const root = dirname(current);
|
|
970
970
|
while (current !== root) {
|
|
971
|
-
if (existsSync3(
|
|
971
|
+
if (existsSync3(join3(current, PROJECT_DIR))) {
|
|
972
972
|
return current;
|
|
973
973
|
}
|
|
974
974
|
const parent = dirname(current);
|
|
975
975
|
if (parent === current) break;
|
|
976
976
|
current = parent;
|
|
977
977
|
}
|
|
978
|
-
if (existsSync3(
|
|
978
|
+
if (existsSync3(join3(current, PROJECT_DIR))) {
|
|
979
979
|
return current;
|
|
980
980
|
}
|
|
981
981
|
return null;
|
|
982
982
|
}
|
|
983
|
-
async function loadProjectMcpId(projectRoot) {
|
|
984
|
-
const settingsPath = join4(projectRoot, PROJECT_DIR, SETTINGS_FILE);
|
|
985
|
-
try {
|
|
986
|
-
const content = await readFile3(settingsPath, "utf-8");
|
|
987
|
-
const settings = JSON.parse(content);
|
|
988
|
-
return settings.mcp?.id ?? null;
|
|
989
|
-
} catch {
|
|
990
|
-
return null;
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
983
|
var DEFAULT_IGNORE_PATTERNS = [
|
|
994
984
|
".waniwani",
|
|
995
985
|
".git",
|
|
@@ -1009,10 +999,10 @@ var DEFAULT_IGNORE_PATTERNS = [
|
|
|
1009
999
|
async function loadIgnorePatterns(projectRoot) {
|
|
1010
1000
|
const ig = ignore();
|
|
1011
1001
|
ig.add(DEFAULT_IGNORE_PATTERNS);
|
|
1012
|
-
const gitignorePath =
|
|
1002
|
+
const gitignorePath = join3(projectRoot, ".gitignore");
|
|
1013
1003
|
if (existsSync3(gitignorePath)) {
|
|
1014
1004
|
try {
|
|
1015
|
-
const content = await
|
|
1005
|
+
const content = await readFile2(gitignorePath, "utf-8");
|
|
1016
1006
|
ig.add(content);
|
|
1017
1007
|
} catch {
|
|
1018
1008
|
}
|
|
@@ -1025,7 +1015,7 @@ async function collectFiles(projectRoot) {
|
|
|
1025
1015
|
async function walk(dir) {
|
|
1026
1016
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
1027
1017
|
for (const entry of entries) {
|
|
1028
|
-
const fullPath =
|
|
1018
|
+
const fullPath = join3(dir, entry.name);
|
|
1029
1019
|
const relativePath = relative(projectRoot, fullPath);
|
|
1030
1020
|
if (ig.ignores(relativePath)) {
|
|
1031
1021
|
continue;
|
|
@@ -1034,7 +1024,7 @@ async function collectFiles(projectRoot) {
|
|
|
1034
1024
|
await walk(fullPath);
|
|
1035
1025
|
} else if (entry.isFile()) {
|
|
1036
1026
|
try {
|
|
1037
|
-
const content = await
|
|
1027
|
+
const content = await readFile2(fullPath);
|
|
1038
1028
|
const isBinary = isBinaryPath(fullPath) || detectBinary(content);
|
|
1039
1029
|
files.push({
|
|
1040
1030
|
path: relativePath,
|
|
@@ -1055,20 +1045,20 @@ async function pullFilesFromGithub(mcpId, targetDir) {
|
|
|
1055
1045
|
);
|
|
1056
1046
|
const writtenFiles = [];
|
|
1057
1047
|
for (const file of result.files) {
|
|
1058
|
-
const localPath =
|
|
1048
|
+
const localPath = join3(targetDir, file.path);
|
|
1059
1049
|
const dir = dirname(localPath);
|
|
1060
|
-
await
|
|
1050
|
+
await mkdir2(dir, { recursive: true });
|
|
1061
1051
|
if (file.encoding === "base64") {
|
|
1062
|
-
await
|
|
1052
|
+
await writeFile2(localPath, Buffer.from(file.content, "base64"));
|
|
1063
1053
|
} else {
|
|
1064
|
-
await
|
|
1054
|
+
await writeFile2(localPath, file.content, "utf8");
|
|
1065
1055
|
}
|
|
1066
1056
|
writtenFiles.push(file.path);
|
|
1067
1057
|
}
|
|
1068
1058
|
return { count: writtenFiles.length, files: writtenFiles };
|
|
1069
1059
|
}
|
|
1070
1060
|
async function collectSingleFile(projectRoot, filePath) {
|
|
1071
|
-
const fullPath =
|
|
1061
|
+
const fullPath = join3(projectRoot, filePath);
|
|
1072
1062
|
const relativePath = relative(projectRoot, fullPath);
|
|
1073
1063
|
if (!existsSync3(fullPath)) {
|
|
1074
1064
|
return null;
|
|
@@ -1078,7 +1068,7 @@ async function collectSingleFile(projectRoot, filePath) {
|
|
|
1078
1068
|
if (!fileStat.isFile()) {
|
|
1079
1069
|
return null;
|
|
1080
1070
|
}
|
|
1081
|
-
const content = await
|
|
1071
|
+
const content = await readFile2(fullPath);
|
|
1082
1072
|
const isBinary = isBinaryPath(fullPath) || detectBinary(content);
|
|
1083
1073
|
return {
|
|
1084
1074
|
path: relativePath,
|
|
@@ -1152,9 +1142,6 @@ var devCommand = new Command7("dev").description("Start live development with sa
|
|
|
1152
1142
|
);
|
|
1153
1143
|
}
|
|
1154
1144
|
let mcpId = options.mcpId;
|
|
1155
|
-
if (!mcpId) {
|
|
1156
|
-
mcpId = await loadProjectMcpId(projectRoot);
|
|
1157
|
-
}
|
|
1158
1145
|
if (!mcpId) {
|
|
1159
1146
|
mcpId = await config.getMcpId();
|
|
1160
1147
|
}
|
|
@@ -1182,6 +1169,7 @@ var devCommand = new Command7("dev").description("Start live development with sa
|
|
|
1182
1169
|
}
|
|
1183
1170
|
sessionId = existing.id;
|
|
1184
1171
|
}
|
|
1172
|
+
await config.setSessionId(sessionId);
|
|
1185
1173
|
spinner.text = "Syncing files to sandbox...";
|
|
1186
1174
|
const files = await collectFiles(projectRoot);
|
|
1187
1175
|
if (files.length > 0) {
|
|
@@ -1270,8 +1258,8 @@ var listCommand = new Command8("list").description("List files in the MCP sandbo
|
|
|
1270
1258
|
const globalOptions = command.optsWithGlobals();
|
|
1271
1259
|
const json = globalOptions.json ?? false;
|
|
1272
1260
|
try {
|
|
1273
|
-
|
|
1274
|
-
const sessionId = await requireSessionId(
|
|
1261
|
+
await requireMcpId(options.mcpId);
|
|
1262
|
+
const sessionId = await requireSessionId();
|
|
1275
1263
|
const spinner = ora5(`Listing ${path}...`).start();
|
|
1276
1264
|
const result = await api.get(
|
|
1277
1265
|
`/api/mcp/sessions/${sessionId}/files/list?path=${encodeURIComponent(path)}`
|
|
@@ -1308,15 +1296,15 @@ function formatSize(bytes) {
|
|
|
1308
1296
|
}
|
|
1309
1297
|
|
|
1310
1298
|
// src/commands/mcp/file/read.ts
|
|
1311
|
-
import { writeFile as
|
|
1299
|
+
import { writeFile as writeFile3 } from "fs/promises";
|
|
1312
1300
|
import { Command as Command9 } from "commander";
|
|
1313
1301
|
import ora6 from "ora";
|
|
1314
1302
|
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) => {
|
|
1315
1303
|
const globalOptions = command.optsWithGlobals();
|
|
1316
1304
|
const json = globalOptions.json ?? false;
|
|
1317
1305
|
try {
|
|
1318
|
-
|
|
1319
|
-
const sessionId = await requireSessionId(
|
|
1306
|
+
await requireMcpId(options.mcpId);
|
|
1307
|
+
const sessionId = await requireSessionId();
|
|
1320
1308
|
const encoding = options.base64 ? "base64" : "utf8";
|
|
1321
1309
|
const spinner = ora6(`Reading ${path}...`).start();
|
|
1322
1310
|
const result = await api.get(
|
|
@@ -1328,7 +1316,7 @@ var readCommand = new Command9("read").description("Read a file from the MCP san
|
|
|
1328
1316
|
}
|
|
1329
1317
|
if (options.output) {
|
|
1330
1318
|
const buffer = result.encoding === "base64" ? Buffer.from(result.content, "base64") : Buffer.from(result.content, "utf8");
|
|
1331
|
-
await
|
|
1319
|
+
await writeFile3(options.output, buffer);
|
|
1332
1320
|
if (json) {
|
|
1333
1321
|
formatOutput({ path, savedTo: options.output }, true);
|
|
1334
1322
|
} else {
|
|
@@ -1349,15 +1337,15 @@ var readCommand = new Command9("read").description("Read a file from the MCP san
|
|
|
1349
1337
|
});
|
|
1350
1338
|
|
|
1351
1339
|
// src/commands/mcp/file/write.ts
|
|
1352
|
-
import { readFile as
|
|
1340
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
1353
1341
|
import { Command as Command10 } from "commander";
|
|
1354
1342
|
import ora7 from "ora";
|
|
1355
1343
|
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) => {
|
|
1356
1344
|
const globalOptions = command.optsWithGlobals();
|
|
1357
1345
|
const json = globalOptions.json ?? false;
|
|
1358
1346
|
try {
|
|
1359
|
-
|
|
1360
|
-
const sessionId = await requireSessionId(
|
|
1347
|
+
await requireMcpId(options.mcpId);
|
|
1348
|
+
const sessionId = await requireSessionId();
|
|
1361
1349
|
let content;
|
|
1362
1350
|
let encoding = "utf8";
|
|
1363
1351
|
if (options.content) {
|
|
@@ -1366,7 +1354,7 @@ var writeCommand = new Command10("write").description("Write a file to the MCP s
|
|
|
1366
1354
|
encoding = "base64";
|
|
1367
1355
|
}
|
|
1368
1356
|
} else if (options.file) {
|
|
1369
|
-
const fileBuffer = await
|
|
1357
|
+
const fileBuffer = await readFile3(options.file);
|
|
1370
1358
|
if (options.base64) {
|
|
1371
1359
|
content = fileBuffer.toString("base64");
|
|
1372
1360
|
encoding = "base64";
|
|
@@ -1403,20 +1391,20 @@ var fileCommand = new Command11("file").description("File operations in MCP sand
|
|
|
1403
1391
|
|
|
1404
1392
|
// src/commands/mcp/init.ts
|
|
1405
1393
|
import { existsSync as existsSync4 } from "fs";
|
|
1406
|
-
import { readFile as
|
|
1407
|
-
import { join as
|
|
1394
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
1395
|
+
import { join as join4 } from "path";
|
|
1408
1396
|
import { Command as Command12 } from "commander";
|
|
1409
1397
|
import { execa } from "execa";
|
|
1410
1398
|
import ora8 from "ora";
|
|
1411
1399
|
async function loadParentConfig(cwd) {
|
|
1412
|
-
const parentConfigPath =
|
|
1400
|
+
const parentConfigPath = join4(cwd, LOCAL_CONFIG_DIR, CONFIG_FILE_NAME);
|
|
1413
1401
|
if (!existsSync4(parentConfigPath)) {
|
|
1414
1402
|
return null;
|
|
1415
1403
|
}
|
|
1416
1404
|
try {
|
|
1417
|
-
const content = await
|
|
1405
|
+
const content = await readFile4(parentConfigPath, "utf-8");
|
|
1418
1406
|
const config2 = JSON.parse(content);
|
|
1419
|
-
const {
|
|
1407
|
+
const { mcpId: _, sessionId: __, ...rest } = config2;
|
|
1420
1408
|
return rest;
|
|
1421
1409
|
} catch {
|
|
1422
1410
|
return null;
|
|
@@ -1427,7 +1415,7 @@ var initCommand = new Command12("init").description("Create a new MCP project").
|
|
|
1427
1415
|
const json = globalOptions.json ?? false;
|
|
1428
1416
|
try {
|
|
1429
1417
|
const cwd = process.cwd();
|
|
1430
|
-
const projectDir =
|
|
1418
|
+
const projectDir = join4(cwd, name);
|
|
1431
1419
|
if (existsSync4(projectDir)) {
|
|
1432
1420
|
if (json) {
|
|
1433
1421
|
formatOutput(
|
|
@@ -1454,10 +1442,7 @@ var initCommand = new Command12("init").description("Create a new MCP project").
|
|
|
1454
1442
|
const parentConfig = await loadParentConfig(cwd);
|
|
1455
1443
|
await initConfigAt(projectDir, {
|
|
1456
1444
|
...parentConfig,
|
|
1457
|
-
|
|
1458
|
-
id: result.repository.id,
|
|
1459
|
-
name: result.repository.name
|
|
1460
|
-
}
|
|
1445
|
+
mcpId: result.repository.id
|
|
1461
1446
|
});
|
|
1462
1447
|
spinner.succeed("MCP project created");
|
|
1463
1448
|
} else {
|
|
@@ -1579,8 +1564,8 @@ var logsCommand = new Command14("logs").description("Stream logs from the MCP se
|
|
|
1579
1564
|
process.on("SIGINT", cleanup);
|
|
1580
1565
|
process.on("SIGTERM", cleanup);
|
|
1581
1566
|
try {
|
|
1582
|
-
|
|
1583
|
-
const sessionId = await requireSessionId(
|
|
1567
|
+
await requireMcpId(options.mcpId);
|
|
1568
|
+
const sessionId = await requireSessionId();
|
|
1584
1569
|
const token = await auth.getAccessToken();
|
|
1585
1570
|
if (!token) {
|
|
1586
1571
|
throw new AuthError(
|
|
@@ -1715,8 +1700,8 @@ var runCommandCommand = new Command15("run-command").description("Run a command
|
|
|
1715
1700
|
const globalOptions = command.optsWithGlobals();
|
|
1716
1701
|
const json = globalOptions.json ?? false;
|
|
1717
1702
|
try {
|
|
1718
|
-
|
|
1719
|
-
const sessionId = await requireSessionId(
|
|
1703
|
+
await requireMcpId(options.mcpId);
|
|
1704
|
+
const sessionId = await requireSessionId();
|
|
1720
1705
|
const timeout = options.timeout ? Number.parseInt(options.timeout, 10) : void 0;
|
|
1721
1706
|
const spinner = ora11(`Running: ${cmd} ${args.join(" ")}`.trim()).start();
|
|
1722
1707
|
const result = await api.post(
|
|
@@ -1847,8 +1832,8 @@ var stopCommand = new Command17("stop").description("Stop the development enviro
|
|
|
1847
1832
|
const globalOptions = command.optsWithGlobals();
|
|
1848
1833
|
const json = globalOptions.json ?? false;
|
|
1849
1834
|
try {
|
|
1850
|
-
|
|
1851
|
-
const sessionId = await requireSessionId(
|
|
1835
|
+
await requireMcpId(options.mcpId);
|
|
1836
|
+
const sessionId = await requireSessionId();
|
|
1852
1837
|
const spinner = ora13("Stopping development environment...").start();
|
|
1853
1838
|
try {
|
|
1854
1839
|
await api.post(`/api/mcp/sessions/${sessionId}/server`, {
|
|
@@ -1857,6 +1842,7 @@ var stopCommand = new Command17("stop").description("Stop the development enviro
|
|
|
1857
1842
|
} catch {
|
|
1858
1843
|
}
|
|
1859
1844
|
await api.delete(`/api/mcp/sessions/${sessionId}`);
|
|
1845
|
+
await config.setSessionId(null);
|
|
1860
1846
|
spinner.succeed("Development environment stopped");
|
|
1861
1847
|
if (json) {
|
|
1862
1848
|
formatOutput({ stopped: true }, true);
|
|
@@ -1910,7 +1896,7 @@ var syncCommand = new Command18("sync").description("Pull files from GitHub to l
|
|
|
1910
1896
|
// src/commands/mcp/use.ts
|
|
1911
1897
|
import { Command as Command19 } from "commander";
|
|
1912
1898
|
import ora15 from "ora";
|
|
1913
|
-
var useCommand = new Command19("use").description("Select an MCP to use for subsequent commands").argument("<name>", "Name of the MCP to use").
|
|
1899
|
+
var useCommand = new Command19("use").description("Select an MCP to use for subsequent commands").argument("<name>", "Name of the MCP to use").action(async (name, _options, command) => {
|
|
1914
1900
|
const globalOptions = command.optsWithGlobals();
|
|
1915
1901
|
const json = globalOptions.json ?? false;
|
|
1916
1902
|
try {
|
|
@@ -1925,12 +1911,12 @@ var useCommand = new Command19("use").description("Select an MCP to use for subs
|
|
|
1925
1911
|
`MCP "${name}" not found. Run 'waniwani mcp list' to see available MCPs.`
|
|
1926
1912
|
);
|
|
1927
1913
|
}
|
|
1928
|
-
|
|
1929
|
-
await
|
|
1914
|
+
await config.setMcpId(mcp.id);
|
|
1915
|
+
await config.setSessionId(null);
|
|
1930
1916
|
if (json) {
|
|
1931
|
-
formatOutput({ selected: mcp
|
|
1917
|
+
formatOutput({ selected: mcp }, true);
|
|
1932
1918
|
} else {
|
|
1933
|
-
formatSuccess(`Now using MCP "${name}"
|
|
1919
|
+
formatSuccess(`Now using MCP "${name}"`, false);
|
|
1934
1920
|
console.log();
|
|
1935
1921
|
console.log(` MCP ID: ${mcp.id}`);
|
|
1936
1922
|
console.log();
|