@waniwani/cli 0.0.26 → 0.0.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 +817 -435
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1,209 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import { Command as
|
|
5
|
-
|
|
6
|
-
// src/commands/init.ts
|
|
7
|
-
import { existsSync } from "fs";
|
|
8
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
9
|
-
import { join } from "path";
|
|
10
|
-
import { Command } from "commander";
|
|
4
|
+
import { Command as Command25 } from "commander";
|
|
11
5
|
|
|
12
|
-
// src/
|
|
13
|
-
import
|
|
14
|
-
import { ZodError } from "zod";
|
|
15
|
-
var CLIError = class extends Error {
|
|
16
|
-
constructor(message, code, details) {
|
|
17
|
-
super(message);
|
|
18
|
-
this.code = code;
|
|
19
|
-
this.details = details;
|
|
20
|
-
this.name = "CLIError";
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
var AuthError = class extends CLIError {
|
|
24
|
-
constructor(message, details) {
|
|
25
|
-
super(message, "AUTH_ERROR", details);
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
var SandboxError = class extends CLIError {
|
|
29
|
-
constructor(message, details) {
|
|
30
|
-
super(message, "SANDBOX_ERROR", details);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
var McpError = class extends CLIError {
|
|
34
|
-
constructor(message, details) {
|
|
35
|
-
super(message, "MCP_ERROR", details);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
function handleError(error, json) {
|
|
39
|
-
if (error instanceof ZodError) {
|
|
40
|
-
const message = error.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
41
|
-
outputError("VALIDATION_ERROR", `Invalid input: ${message}`, json);
|
|
42
|
-
} else if (error instanceof CLIError) {
|
|
43
|
-
outputError(error.code, error.message, json, error.details);
|
|
44
|
-
} else if (error instanceof Error) {
|
|
45
|
-
outputError("UNKNOWN_ERROR", error.message, json);
|
|
46
|
-
} else {
|
|
47
|
-
outputError("UNKNOWN_ERROR", String(error), json);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
function outputError(code, message, json, details) {
|
|
51
|
-
if (json) {
|
|
52
|
-
console.error(
|
|
53
|
-
JSON.stringify({ success: false, error: { code, message, details } })
|
|
54
|
-
);
|
|
55
|
-
} else {
|
|
56
|
-
console.error(chalk.red(`Error [${code}]:`), message);
|
|
57
|
-
if (details) {
|
|
58
|
-
console.error(chalk.gray("Details:"), JSON.stringify(details, null, 2));
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// src/lib/output.ts
|
|
6
|
+
// src/commands/dev.ts
|
|
7
|
+
import { relative as relative2 } from "path";
|
|
64
8
|
import chalk2 from "chalk";
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
68
|
-
} else {
|
|
69
|
-
prettyPrint(data);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function formatSuccess(message, json) {
|
|
73
|
-
if (json) {
|
|
74
|
-
console.log(JSON.stringify({ success: true, message }));
|
|
75
|
-
} else {
|
|
76
|
-
console.log(chalk2.green("\u2713"), message);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function formatTable(headers, rows, json) {
|
|
80
|
-
if (json) {
|
|
81
|
-
const data = rows.map(
|
|
82
|
-
(row) => Object.fromEntries(headers.map((header, i) => [header, row[i]]))
|
|
83
|
-
);
|
|
84
|
-
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
85
|
-
} else {
|
|
86
|
-
const colWidths = headers.map(
|
|
87
|
-
(h, i) => Math.max(h.length, ...rows.map((r) => (r[i] || "").length))
|
|
88
|
-
);
|
|
89
|
-
const separator = colWidths.map((w) => "-".repeat(w + 2)).join("+");
|
|
90
|
-
const formatRow = (row) => row.map((cell, i) => ` ${(cell || "").padEnd(colWidths[i])} `).join("|");
|
|
91
|
-
console.log(chalk2.cyan(formatRow(headers)));
|
|
92
|
-
console.log(separator);
|
|
93
|
-
for (const row of rows) {
|
|
94
|
-
console.log(formatRow(row));
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
function formatList(items, json) {
|
|
99
|
-
if (json) {
|
|
100
|
-
const data = Object.fromEntries(
|
|
101
|
-
items.map((item) => [item.label, item.value])
|
|
102
|
-
);
|
|
103
|
-
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
104
|
-
} else {
|
|
105
|
-
const maxLabelLength = Math.max(...items.map((i) => i.label.length));
|
|
106
|
-
items.forEach((item) => {
|
|
107
|
-
console.log(
|
|
108
|
-
`${chalk2.gray(item.label.padEnd(maxLabelLength))} ${chalk2.white(item.value)}`
|
|
109
|
-
);
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
function prettyPrint(data, indent = 0) {
|
|
114
|
-
const prefix = " ".repeat(indent);
|
|
115
|
-
if (Array.isArray(data)) {
|
|
116
|
-
data.forEach((item, index) => {
|
|
117
|
-
console.log(`${prefix}${chalk2.gray(`[${index}]`)}`);
|
|
118
|
-
prettyPrint(item, indent + 1);
|
|
119
|
-
});
|
|
120
|
-
} else if (typeof data === "object" && data !== null) {
|
|
121
|
-
for (const [key, value] of Object.entries(data)) {
|
|
122
|
-
if (typeof value === "object" && value !== null) {
|
|
123
|
-
console.log(`${prefix}${chalk2.gray(key)}:`);
|
|
124
|
-
prettyPrint(value, indent + 1);
|
|
125
|
-
} else {
|
|
126
|
-
console.log(
|
|
127
|
-
`${prefix}${chalk2.gray(key)}: ${chalk2.white(String(value))}`
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
} else {
|
|
132
|
-
console.log(`${prefix}${chalk2.white(String(data))}`);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// src/commands/init.ts
|
|
137
|
-
var PROJECT_CONFIG_DIR = ".waniwani";
|
|
138
|
-
var PROJECT_CONFIG_FILE = "settings.local.json";
|
|
139
|
-
var initCommand = new Command("init").description("Initialize WaniWani project config in current directory").action(async (_, command) => {
|
|
140
|
-
const globalOptions = command.optsWithGlobals();
|
|
141
|
-
const json = globalOptions.json ?? false;
|
|
142
|
-
try {
|
|
143
|
-
const cwd = process.cwd();
|
|
144
|
-
const configDir = join(cwd, PROJECT_CONFIG_DIR);
|
|
145
|
-
const configPath = join(configDir, PROJECT_CONFIG_FILE);
|
|
146
|
-
if (existsSync(configDir)) {
|
|
147
|
-
if (json) {
|
|
148
|
-
formatOutput(
|
|
149
|
-
{ initialized: false, message: "Already initialized" },
|
|
150
|
-
true
|
|
151
|
-
);
|
|
152
|
-
} else {
|
|
153
|
-
console.log("Project already initialized (.waniwani/ exists)");
|
|
154
|
-
}
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
await mkdir(configDir, { recursive: true });
|
|
158
|
-
const defaultConfig = {
|
|
159
|
-
mcpId: null,
|
|
160
|
-
defaults: {}
|
|
161
|
-
};
|
|
162
|
-
await writeFile(
|
|
163
|
-
configPath,
|
|
164
|
-
JSON.stringify(defaultConfig, null, " "),
|
|
165
|
-
"utf-8"
|
|
166
|
-
);
|
|
167
|
-
if (json) {
|
|
168
|
-
formatOutput({ initialized: true, path: configDir }, true);
|
|
169
|
-
} else {
|
|
170
|
-
formatSuccess("Initialized WaniWani project config", false);
|
|
171
|
-
console.log();
|
|
172
|
-
console.log(` Created: ${PROJECT_CONFIG_DIR}/${PROJECT_CONFIG_FILE}`);
|
|
173
|
-
console.log();
|
|
174
|
-
console.log("Now run:");
|
|
175
|
-
console.log(' waniwani mcp create "my-mcp"');
|
|
176
|
-
console.log(" waniwani mcp use <name>");
|
|
177
|
-
}
|
|
178
|
-
} catch (error) {
|
|
179
|
-
handleError(error, json);
|
|
180
|
-
process.exit(1);
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// src/commands/login.ts
|
|
185
|
-
import { spawn } from "child_process";
|
|
186
|
-
import { createServer } from "http";
|
|
187
|
-
import chalk3 from "chalk";
|
|
188
|
-
import { Command as Command2 } from "commander";
|
|
9
|
+
import chokidar from "chokidar";
|
|
10
|
+
import { Command } from "commander";
|
|
189
11
|
import ora from "ora";
|
|
190
12
|
|
|
191
13
|
// src/lib/auth.ts
|
|
192
|
-
import { access, mkdir as
|
|
14
|
+
import { access, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
193
15
|
import { homedir as homedir2 } from "os";
|
|
194
|
-
import { join as
|
|
16
|
+
import { join as join2 } from "path";
|
|
195
17
|
import { z as z2 } from "zod";
|
|
196
18
|
|
|
197
19
|
// src/lib/config.ts
|
|
198
|
-
import { existsSync
|
|
199
|
-
import { mkdir
|
|
20
|
+
import { existsSync } from "fs";
|
|
21
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
200
22
|
import { homedir } from "os";
|
|
201
|
-
import { join
|
|
23
|
+
import { join } from "path";
|
|
202
24
|
import { z } from "zod";
|
|
203
|
-
var LOCAL_DIR =
|
|
204
|
-
var LOCAL_FILE =
|
|
205
|
-
var GLOBAL_DIR =
|
|
206
|
-
var GLOBAL_FILE =
|
|
25
|
+
var LOCAL_DIR = join(process.cwd(), ".waniwani");
|
|
26
|
+
var LOCAL_FILE = join(LOCAL_DIR, "settings.json");
|
|
27
|
+
var GLOBAL_DIR = join(homedir(), ".waniwani");
|
|
28
|
+
var GLOBAL_FILE = join(GLOBAL_DIR, "settings.json");
|
|
207
29
|
var DEFAULT_API_URL = "https://app.waniwani.ai";
|
|
208
30
|
var ConfigSchema = z.object({
|
|
209
31
|
defaults: z.object({ model: z.string(), maxSteps: z.number() }).default({ model: "claude-sonnet-4-20250514", maxSteps: 10 }),
|
|
@@ -216,7 +38,7 @@ var Config = class {
|
|
|
216
38
|
cache = null;
|
|
217
39
|
scope;
|
|
218
40
|
constructor(forceGlobal = false) {
|
|
219
|
-
const useLocal = !forceGlobal &&
|
|
41
|
+
const useLocal = !forceGlobal && existsSync(LOCAL_DIR);
|
|
220
42
|
this.dir = useLocal ? LOCAL_DIR : GLOBAL_DIR;
|
|
221
43
|
this.file = useLocal ? LOCAL_FILE : GLOBAL_FILE;
|
|
222
44
|
this.scope = useLocal ? "local" : "global";
|
|
@@ -235,8 +57,8 @@ var Config = class {
|
|
|
235
57
|
}
|
|
236
58
|
async save(data) {
|
|
237
59
|
this.cache = data;
|
|
238
|
-
await
|
|
239
|
-
await
|
|
60
|
+
await mkdir(this.dir, { recursive: true });
|
|
61
|
+
await writeFile(this.file, JSON.stringify(data, null, " "));
|
|
240
62
|
}
|
|
241
63
|
async getDefaults() {
|
|
242
64
|
return (await this.load()).defaults;
|
|
@@ -271,8 +93,8 @@ var config = new Config();
|
|
|
271
93
|
var globalConfig = new Config(true);
|
|
272
94
|
|
|
273
95
|
// src/lib/auth.ts
|
|
274
|
-
var CONFIG_DIR =
|
|
275
|
-
var AUTH_FILE =
|
|
96
|
+
var CONFIG_DIR = join2(homedir2(), ".waniwani");
|
|
97
|
+
var AUTH_FILE = join2(CONFIG_DIR, "auth.json");
|
|
276
98
|
var AuthStoreSchema = z2.object({
|
|
277
99
|
accessToken: z2.string().nullable().default(null),
|
|
278
100
|
refreshToken: z2.string().nullable().default(null),
|
|
@@ -280,7 +102,7 @@ var AuthStoreSchema = z2.object({
|
|
|
280
102
|
clientId: z2.string().nullable().default(null)
|
|
281
103
|
});
|
|
282
104
|
async function ensureConfigDir() {
|
|
283
|
-
await
|
|
105
|
+
await mkdir2(CONFIG_DIR, { recursive: true });
|
|
284
106
|
}
|
|
285
107
|
async function readAuthStore() {
|
|
286
108
|
await ensureConfigDir();
|
|
@@ -294,7 +116,7 @@ async function readAuthStore() {
|
|
|
294
116
|
}
|
|
295
117
|
async function writeAuthStore(store) {
|
|
296
118
|
await ensureConfigDir();
|
|
297
|
-
await
|
|
119
|
+
await writeFile2(AUTH_FILE, JSON.stringify(store, null, 2), "utf-8");
|
|
298
120
|
}
|
|
299
121
|
var AuthManager = class {
|
|
300
122
|
storeCache = null;
|
|
@@ -359,22 +181,624 @@ var AuthManager = class {
|
|
|
359
181
|
await this.clear();
|
|
360
182
|
return false;
|
|
361
183
|
}
|
|
362
|
-
const data = await response.json();
|
|
363
|
-
await this.setTokens(
|
|
364
|
-
data.access_token,
|
|
365
|
-
data.refresh_token,
|
|
366
|
-
data.expires_in
|
|
184
|
+
const data = await response.json();
|
|
185
|
+
await this.setTokens(
|
|
186
|
+
data.access_token,
|
|
187
|
+
data.refresh_token,
|
|
188
|
+
data.expires_in
|
|
189
|
+
);
|
|
190
|
+
return true;
|
|
191
|
+
} catch {
|
|
192
|
+
await this.clear();
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
var auth = new AuthManager();
|
|
198
|
+
|
|
199
|
+
// src/lib/errors.ts
|
|
200
|
+
import chalk from "chalk";
|
|
201
|
+
import { ZodError } from "zod";
|
|
202
|
+
var CLIError = class extends Error {
|
|
203
|
+
constructor(message, code, details) {
|
|
204
|
+
super(message);
|
|
205
|
+
this.code = code;
|
|
206
|
+
this.details = details;
|
|
207
|
+
this.name = "CLIError";
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
var AuthError = class extends CLIError {
|
|
211
|
+
constructor(message, details) {
|
|
212
|
+
super(message, "AUTH_ERROR", details);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
var SandboxError = class extends CLIError {
|
|
216
|
+
constructor(message, details) {
|
|
217
|
+
super(message, "SANDBOX_ERROR", details);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
var McpError = class extends CLIError {
|
|
221
|
+
constructor(message, details) {
|
|
222
|
+
super(message, "MCP_ERROR", details);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
function handleError(error, json) {
|
|
226
|
+
if (error instanceof ZodError) {
|
|
227
|
+
const message = error.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
228
|
+
outputError("VALIDATION_ERROR", `Invalid input: ${message}`, json);
|
|
229
|
+
} else if (error instanceof CLIError) {
|
|
230
|
+
outputError(error.code, error.message, json, error.details);
|
|
231
|
+
} else if (error instanceof Error) {
|
|
232
|
+
outputError("UNKNOWN_ERROR", error.message, json);
|
|
233
|
+
} else {
|
|
234
|
+
outputError("UNKNOWN_ERROR", String(error), json);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function outputError(code, message, json, details) {
|
|
238
|
+
if (json) {
|
|
239
|
+
console.error(
|
|
240
|
+
JSON.stringify({ success: false, error: { code, message, details } })
|
|
241
|
+
);
|
|
242
|
+
} else {
|
|
243
|
+
console.error(chalk.red(`Error [${code}]:`), message);
|
|
244
|
+
if (details) {
|
|
245
|
+
console.error(chalk.gray("Details:"), JSON.stringify(details, null, 2));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/lib/api.ts
|
|
251
|
+
var ApiError = class extends CLIError {
|
|
252
|
+
constructor(message, code, statusCode, details) {
|
|
253
|
+
super(message, code, details);
|
|
254
|
+
this.statusCode = statusCode;
|
|
255
|
+
this.name = "ApiError";
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
async function request(method, path, options) {
|
|
259
|
+
const {
|
|
260
|
+
body,
|
|
261
|
+
requireAuth = true,
|
|
262
|
+
headers: extraHeaders = {}
|
|
263
|
+
} = options || {};
|
|
264
|
+
const headers = {
|
|
265
|
+
"Content-Type": "application/json",
|
|
266
|
+
...extraHeaders
|
|
267
|
+
};
|
|
268
|
+
if (requireAuth) {
|
|
269
|
+
const token = await auth.getAccessToken();
|
|
270
|
+
if (!token) {
|
|
271
|
+
throw new AuthError(
|
|
272
|
+
"Not logged in. Run 'waniwani login' to authenticate."
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
headers.Authorization = `Bearer ${token}`;
|
|
276
|
+
}
|
|
277
|
+
const baseUrl = await config.getApiUrl();
|
|
278
|
+
const url = `${baseUrl}${path}`;
|
|
279
|
+
const response = await fetch(url, {
|
|
280
|
+
method,
|
|
281
|
+
headers,
|
|
282
|
+
body: body ? JSON.stringify(body) : void 0
|
|
283
|
+
});
|
|
284
|
+
if (response.status === 204) {
|
|
285
|
+
return void 0;
|
|
286
|
+
}
|
|
287
|
+
let data;
|
|
288
|
+
let rawBody;
|
|
289
|
+
try {
|
|
290
|
+
rawBody = await response.text();
|
|
291
|
+
data = JSON.parse(rawBody);
|
|
292
|
+
} catch {
|
|
293
|
+
throw new ApiError(
|
|
294
|
+
rawBody || `Request failed with status ${response.status}`,
|
|
295
|
+
"API_ERROR",
|
|
296
|
+
response.status,
|
|
297
|
+
{ statusText: response.statusText }
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
if (!response.ok || data.error) {
|
|
301
|
+
const errorMessage = data.error?.message || data.message || data.error || rawBody || `Request failed with status ${response.status}`;
|
|
302
|
+
const errorCode = data.error?.code || data.code || "API_ERROR";
|
|
303
|
+
const errorDetails = {
|
|
304
|
+
...data.error?.details,
|
|
305
|
+
statusText: response.statusText,
|
|
306
|
+
...data.error ? {} : { rawResponse: data }
|
|
307
|
+
};
|
|
308
|
+
const error = {
|
|
309
|
+
code: errorCode,
|
|
310
|
+
message: errorMessage,
|
|
311
|
+
details: errorDetails
|
|
312
|
+
};
|
|
313
|
+
if (response.status === 401) {
|
|
314
|
+
const refreshed = await auth.tryRefreshToken();
|
|
315
|
+
if (refreshed) {
|
|
316
|
+
return request(method, path, options);
|
|
317
|
+
}
|
|
318
|
+
throw new AuthError(
|
|
319
|
+
"Session expired. Run 'waniwani login' to re-authenticate."
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
throw new ApiError(
|
|
323
|
+
error.message,
|
|
324
|
+
error.code,
|
|
325
|
+
response.status,
|
|
326
|
+
error.details
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
return data.data;
|
|
330
|
+
}
|
|
331
|
+
var api = {
|
|
332
|
+
get: (path, options) => request("GET", path, options),
|
|
333
|
+
post: (path, body, options) => request("POST", path, { body, ...options }),
|
|
334
|
+
delete: (path, options) => request("DELETE", path, options),
|
|
335
|
+
getBaseUrl: () => config.getApiUrl()
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
// src/lib/sync.ts
|
|
339
|
+
import { existsSync as existsSync2 } from "fs";
|
|
340
|
+
import { mkdir as mkdir3, readdir, readFile as readFile3, stat, writeFile as writeFile3 } from "fs/promises";
|
|
341
|
+
import { dirname, join as join3, relative } from "path";
|
|
342
|
+
import ignore from "ignore";
|
|
343
|
+
|
|
344
|
+
// src/lib/utils.ts
|
|
345
|
+
function debounce(fn, delay) {
|
|
346
|
+
let timeoutId;
|
|
347
|
+
return (...args) => {
|
|
348
|
+
clearTimeout(timeoutId);
|
|
349
|
+
timeoutId = setTimeout(() => fn(...args), delay);
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
353
|
+
".png",
|
|
354
|
+
".jpg",
|
|
355
|
+
".jpeg",
|
|
356
|
+
".gif",
|
|
357
|
+
".ico",
|
|
358
|
+
".webp",
|
|
359
|
+
".svg",
|
|
360
|
+
".woff",
|
|
361
|
+
".woff2",
|
|
362
|
+
".ttf",
|
|
363
|
+
".eot",
|
|
364
|
+
".otf",
|
|
365
|
+
".zip",
|
|
366
|
+
".tar",
|
|
367
|
+
".gz",
|
|
368
|
+
".pdf",
|
|
369
|
+
".exe",
|
|
370
|
+
".dll",
|
|
371
|
+
".so",
|
|
372
|
+
".dylib",
|
|
373
|
+
".bin",
|
|
374
|
+
".mp3",
|
|
375
|
+
".mp4",
|
|
376
|
+
".wav",
|
|
377
|
+
".ogg",
|
|
378
|
+
".webm"
|
|
379
|
+
]);
|
|
380
|
+
function isBinaryPath(filePath) {
|
|
381
|
+
const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
|
|
382
|
+
return BINARY_EXTENSIONS.has(ext);
|
|
383
|
+
}
|
|
384
|
+
function detectBinary(buffer) {
|
|
385
|
+
const sample = buffer.subarray(0, 8192);
|
|
386
|
+
return sample.includes(0);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// src/lib/sync.ts
|
|
390
|
+
var PROJECT_DIR = ".waniwani";
|
|
391
|
+
var SETTINGS_FILE = "settings.json";
|
|
392
|
+
async function findProjectRoot(startDir) {
|
|
393
|
+
let current = startDir;
|
|
394
|
+
const root = dirname(current);
|
|
395
|
+
while (current !== root) {
|
|
396
|
+
if (existsSync2(join3(current, PROJECT_DIR))) {
|
|
397
|
+
return current;
|
|
398
|
+
}
|
|
399
|
+
const parent = dirname(current);
|
|
400
|
+
if (parent === current) break;
|
|
401
|
+
current = parent;
|
|
402
|
+
}
|
|
403
|
+
if (existsSync2(join3(current, PROJECT_DIR))) {
|
|
404
|
+
return current;
|
|
405
|
+
}
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
async function loadProjectMcpId(projectRoot) {
|
|
409
|
+
const settingsPath = join3(projectRoot, PROJECT_DIR, SETTINGS_FILE);
|
|
410
|
+
try {
|
|
411
|
+
const content = await readFile3(settingsPath, "utf-8");
|
|
412
|
+
const settings = JSON.parse(content);
|
|
413
|
+
return settings.mcpId ?? null;
|
|
414
|
+
} catch {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
var DEFAULT_IGNORE_PATTERNS = [
|
|
419
|
+
".waniwani",
|
|
420
|
+
".git",
|
|
421
|
+
"node_modules",
|
|
422
|
+
".env",
|
|
423
|
+
".env.*",
|
|
424
|
+
".DS_Store",
|
|
425
|
+
"*.log",
|
|
426
|
+
".cache",
|
|
427
|
+
"dist",
|
|
428
|
+
"coverage",
|
|
429
|
+
".turbo",
|
|
430
|
+
".next",
|
|
431
|
+
".nuxt",
|
|
432
|
+
".vercel"
|
|
433
|
+
];
|
|
434
|
+
async function loadIgnorePatterns(projectRoot) {
|
|
435
|
+
const ig = ignore();
|
|
436
|
+
ig.add(DEFAULT_IGNORE_PATTERNS);
|
|
437
|
+
const gitignorePath = join3(projectRoot, ".gitignore");
|
|
438
|
+
if (existsSync2(gitignorePath)) {
|
|
439
|
+
try {
|
|
440
|
+
const content = await readFile3(gitignorePath, "utf-8");
|
|
441
|
+
ig.add(content);
|
|
442
|
+
} catch {
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return ig;
|
|
446
|
+
}
|
|
447
|
+
async function collectFiles(projectRoot) {
|
|
448
|
+
const ig = await loadIgnorePatterns(projectRoot);
|
|
449
|
+
const files = [];
|
|
450
|
+
async function walk(dir) {
|
|
451
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
452
|
+
for (const entry of entries) {
|
|
453
|
+
const fullPath = join3(dir, entry.name);
|
|
454
|
+
const relativePath = relative(projectRoot, fullPath);
|
|
455
|
+
if (ig.ignores(relativePath)) {
|
|
456
|
+
continue;
|
|
457
|
+
}
|
|
458
|
+
if (entry.isDirectory()) {
|
|
459
|
+
await walk(fullPath);
|
|
460
|
+
} else if (entry.isFile()) {
|
|
461
|
+
try {
|
|
462
|
+
const content = await readFile3(fullPath);
|
|
463
|
+
const isBinary = isBinaryPath(fullPath) || detectBinary(content);
|
|
464
|
+
files.push({
|
|
465
|
+
path: relativePath,
|
|
466
|
+
content: isBinary ? content.toString("base64") : content.toString("utf8"),
|
|
467
|
+
encoding: isBinary ? "base64" : "utf8"
|
|
468
|
+
});
|
|
469
|
+
} catch {
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
await walk(projectRoot);
|
|
475
|
+
return files;
|
|
476
|
+
}
|
|
477
|
+
async function pullFilesFromSandbox(mcpId, targetDir) {
|
|
478
|
+
const result = await api.get(
|
|
479
|
+
`/api/mcp/sandboxes/${mcpId}/files/pull`
|
|
480
|
+
);
|
|
481
|
+
const writtenFiles = [];
|
|
482
|
+
for (const file of result.files) {
|
|
483
|
+
const localPath = join3(targetDir, file.path);
|
|
484
|
+
const dir = dirname(localPath);
|
|
485
|
+
await mkdir3(dir, { recursive: true });
|
|
486
|
+
if (file.encoding === "base64") {
|
|
487
|
+
await writeFile3(localPath, Buffer.from(file.content, "base64"));
|
|
488
|
+
} else {
|
|
489
|
+
await writeFile3(localPath, file.content, "utf8");
|
|
490
|
+
}
|
|
491
|
+
writtenFiles.push(file.path);
|
|
492
|
+
}
|
|
493
|
+
return { count: writtenFiles.length, files: writtenFiles };
|
|
494
|
+
}
|
|
495
|
+
async function collectSingleFile(projectRoot, filePath) {
|
|
496
|
+
const fullPath = join3(projectRoot, filePath);
|
|
497
|
+
const relativePath = relative(projectRoot, fullPath);
|
|
498
|
+
if (!existsSync2(fullPath)) {
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
501
|
+
try {
|
|
502
|
+
const fileStat = await stat(fullPath);
|
|
503
|
+
if (!fileStat.isFile()) {
|
|
504
|
+
return null;
|
|
505
|
+
}
|
|
506
|
+
const content = await readFile3(fullPath);
|
|
507
|
+
const isBinary = isBinaryPath(fullPath) || detectBinary(content);
|
|
508
|
+
return {
|
|
509
|
+
path: relativePath,
|
|
510
|
+
content: isBinary ? content.toString("base64") : content.toString("utf8"),
|
|
511
|
+
encoding: isBinary ? "base64" : "utf8"
|
|
512
|
+
};
|
|
513
|
+
} catch {
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// src/commands/dev.ts
|
|
519
|
+
var BATCH_SIZE = 50;
|
|
520
|
+
var DEFAULT_DEBOUNCE_MS = 300;
|
|
521
|
+
var devCommand = new Command("dev").description("Watch and sync files to MCP sandbox").option("--no-initial-sync", "Skip initial sync of all files").option(
|
|
522
|
+
"--debounce <ms>",
|
|
523
|
+
"Debounce delay in milliseconds",
|
|
524
|
+
String(DEFAULT_DEBOUNCE_MS)
|
|
525
|
+
).action(async (options, command) => {
|
|
526
|
+
const globalOptions = command.optsWithGlobals();
|
|
527
|
+
const json = globalOptions.json ?? false;
|
|
528
|
+
try {
|
|
529
|
+
const cwd = process.cwd();
|
|
530
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
531
|
+
if (!projectRoot) {
|
|
532
|
+
throw new CLIError(
|
|
533
|
+
"Not in a WaniWani project. Run 'waniwani init <name>' first.",
|
|
534
|
+
"NOT_IN_PROJECT"
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
const mcpId = await loadProjectMcpId(projectRoot);
|
|
538
|
+
if (!mcpId) {
|
|
539
|
+
throw new CLIError(
|
|
540
|
+
"No MCP ID found in project config. Run 'waniwani init <name>' first.",
|
|
541
|
+
"NO_MCP_ID"
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
if (options.initialSync !== false) {
|
|
545
|
+
const spinner = ora("Initial sync...").start();
|
|
546
|
+
const files = await collectFiles(projectRoot);
|
|
547
|
+
if (files.length > 0) {
|
|
548
|
+
const totalBatches = Math.ceil(files.length / BATCH_SIZE);
|
|
549
|
+
let synced = 0;
|
|
550
|
+
for (let i = 0; i < totalBatches; i++) {
|
|
551
|
+
const batch = files.slice(i * BATCH_SIZE, (i + 1) * BATCH_SIZE);
|
|
552
|
+
spinner.text = `Syncing (${i + 1}/${totalBatches})...`;
|
|
553
|
+
const result = await api.post(
|
|
554
|
+
`/api/mcp/sandboxes/${mcpId}/files`,
|
|
555
|
+
{
|
|
556
|
+
files: batch.map((f) => ({
|
|
557
|
+
path: f.path,
|
|
558
|
+
content: f.content,
|
|
559
|
+
encoding: f.encoding
|
|
560
|
+
}))
|
|
561
|
+
}
|
|
562
|
+
);
|
|
563
|
+
synced += result.written.length;
|
|
564
|
+
}
|
|
565
|
+
spinner.succeed(`Initial sync complete (${synced} files)`);
|
|
566
|
+
} else {
|
|
567
|
+
spinner.info("No files to sync");
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
const ig = await loadIgnorePatterns(projectRoot);
|
|
571
|
+
const debounceMs = Number.parseInt(options.debounce, 10) || DEFAULT_DEBOUNCE_MS;
|
|
572
|
+
const syncFile = debounce(async (filePath) => {
|
|
573
|
+
const relativePath = relative2(projectRoot, filePath);
|
|
574
|
+
if (ig.ignores(relativePath)) {
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
const file = await collectSingleFile(projectRoot, relativePath);
|
|
578
|
+
if (!file) {
|
|
579
|
+
console.log(chalk2.yellow("Skipped:"), relativePath);
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
try {
|
|
583
|
+
await api.post(
|
|
584
|
+
`/api/mcp/sandboxes/${mcpId}/files`,
|
|
585
|
+
{
|
|
586
|
+
files: [
|
|
587
|
+
{
|
|
588
|
+
path: file.path,
|
|
589
|
+
content: file.content,
|
|
590
|
+
encoding: file.encoding
|
|
591
|
+
}
|
|
592
|
+
]
|
|
593
|
+
}
|
|
594
|
+
);
|
|
595
|
+
console.log(chalk2.green("Synced:"), relativePath);
|
|
596
|
+
} catch (error) {
|
|
597
|
+
console.log(chalk2.red("Failed:"), relativePath);
|
|
598
|
+
if (globalOptions.verbose) {
|
|
599
|
+
console.error(error);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}, debounceMs);
|
|
603
|
+
console.log();
|
|
604
|
+
console.log(chalk2.bold("Watching for changes..."));
|
|
605
|
+
console.log(chalk2.dim("Press Ctrl+C to stop"));
|
|
606
|
+
console.log();
|
|
607
|
+
const watcher = chokidar.watch(projectRoot, {
|
|
608
|
+
ignored: (path) => {
|
|
609
|
+
const relativePath = relative2(projectRoot, path);
|
|
610
|
+
return ig.ignores(relativePath);
|
|
611
|
+
},
|
|
612
|
+
persistent: true,
|
|
613
|
+
ignoreInitial: true,
|
|
614
|
+
awaitWriteFinish: {
|
|
615
|
+
stabilityThreshold: 100,
|
|
616
|
+
pollInterval: 100
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
watcher.on("add", (path) => syncFile(path)).on("change", (path) => syncFile(path)).on("unlink", (path) => {
|
|
620
|
+
const relativePath = relative2(projectRoot, path);
|
|
621
|
+
console.log(chalk2.yellow("Deleted (local only):"), relativePath);
|
|
622
|
+
});
|
|
623
|
+
const cleanup = () => {
|
|
624
|
+
console.log();
|
|
625
|
+
console.log(chalk2.dim("Stopping watcher..."));
|
|
626
|
+
watcher.close().then(() => {
|
|
627
|
+
process.exit(0);
|
|
628
|
+
});
|
|
629
|
+
};
|
|
630
|
+
process.on("SIGINT", cleanup);
|
|
631
|
+
process.on("SIGTERM", cleanup);
|
|
632
|
+
} catch (error) {
|
|
633
|
+
handleError(error, json);
|
|
634
|
+
process.exit(1);
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
// src/commands/init.ts
|
|
639
|
+
import { existsSync as existsSync3 } from "fs";
|
|
640
|
+
import { mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
|
|
641
|
+
import { join as join4 } from "path";
|
|
642
|
+
import { Command as Command2 } from "commander";
|
|
643
|
+
import ora2 from "ora";
|
|
644
|
+
|
|
645
|
+
// src/lib/output.ts
|
|
646
|
+
import chalk3 from "chalk";
|
|
647
|
+
function formatOutput(data, json) {
|
|
648
|
+
if (json) {
|
|
649
|
+
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
650
|
+
} else {
|
|
651
|
+
prettyPrint(data);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
function formatSuccess(message, json) {
|
|
655
|
+
if (json) {
|
|
656
|
+
console.log(JSON.stringify({ success: true, message }));
|
|
657
|
+
} else {
|
|
658
|
+
console.log(chalk3.green("\u2713"), message);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
function formatTable(headers, rows, json) {
|
|
662
|
+
if (json) {
|
|
663
|
+
const data = rows.map(
|
|
664
|
+
(row) => Object.fromEntries(headers.map((header, i) => [header, row[i]]))
|
|
665
|
+
);
|
|
666
|
+
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
667
|
+
} else {
|
|
668
|
+
const colWidths = headers.map(
|
|
669
|
+
(h, i) => Math.max(h.length, ...rows.map((r) => (r[i] || "").length))
|
|
670
|
+
);
|
|
671
|
+
const separator = colWidths.map((w) => "-".repeat(w + 2)).join("+");
|
|
672
|
+
const formatRow = (row) => row.map((cell, i) => ` ${(cell || "").padEnd(colWidths[i])} `).join("|");
|
|
673
|
+
console.log(chalk3.cyan(formatRow(headers)));
|
|
674
|
+
console.log(separator);
|
|
675
|
+
for (const row of rows) {
|
|
676
|
+
console.log(formatRow(row));
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
function formatList(items, json) {
|
|
681
|
+
if (json) {
|
|
682
|
+
const data = Object.fromEntries(
|
|
683
|
+
items.map((item) => [item.label, item.value])
|
|
684
|
+
);
|
|
685
|
+
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
686
|
+
} else {
|
|
687
|
+
const maxLabelLength = Math.max(...items.map((i) => i.label.length));
|
|
688
|
+
items.forEach((item) => {
|
|
689
|
+
console.log(
|
|
690
|
+
`${chalk3.gray(item.label.padEnd(maxLabelLength))} ${chalk3.white(item.value)}`
|
|
691
|
+
);
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
function prettyPrint(data, indent = 0) {
|
|
696
|
+
const prefix = " ".repeat(indent);
|
|
697
|
+
if (Array.isArray(data)) {
|
|
698
|
+
data.forEach((item, index) => {
|
|
699
|
+
console.log(`${prefix}${chalk3.gray(`[${index}]`)}`);
|
|
700
|
+
prettyPrint(item, indent + 1);
|
|
701
|
+
});
|
|
702
|
+
} else if (typeof data === "object" && data !== null) {
|
|
703
|
+
for (const [key, value] of Object.entries(data)) {
|
|
704
|
+
if (typeof value === "object" && value !== null) {
|
|
705
|
+
console.log(`${prefix}${chalk3.gray(key)}:`);
|
|
706
|
+
prettyPrint(value, indent + 1);
|
|
707
|
+
} else {
|
|
708
|
+
console.log(
|
|
709
|
+
`${prefix}${chalk3.gray(key)}: ${chalk3.white(String(value))}`
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
} else {
|
|
714
|
+
console.log(`${prefix}${chalk3.white(String(data))}`);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// src/commands/init.ts
|
|
719
|
+
var PROJECT_CONFIG_DIR = ".waniwani";
|
|
720
|
+
var PROJECT_CONFIG_FILE = "settings.json";
|
|
721
|
+
var initCommand = new Command2("init").description("Create a new MCP project from template").argument("<name>", "Name for the MCP project").action(async (name, _, command) => {
|
|
722
|
+
const globalOptions = command.optsWithGlobals();
|
|
723
|
+
const json = globalOptions.json ?? false;
|
|
724
|
+
try {
|
|
725
|
+
const cwd = process.cwd();
|
|
726
|
+
const projectDir = join4(cwd, name);
|
|
727
|
+
if (existsSync3(projectDir)) {
|
|
728
|
+
if (json) {
|
|
729
|
+
formatOutput(
|
|
730
|
+
{
|
|
731
|
+
success: false,
|
|
732
|
+
error: `Directory "${name}" already exists`
|
|
733
|
+
},
|
|
734
|
+
true
|
|
735
|
+
);
|
|
736
|
+
} else {
|
|
737
|
+
console.error(`Error: Directory "${name}" already exists`);
|
|
738
|
+
}
|
|
739
|
+
process.exit(1);
|
|
740
|
+
}
|
|
741
|
+
const spinner = ora2("Creating MCP sandbox...").start();
|
|
742
|
+
const result = await api.post("/api/mcp/sandboxes", {
|
|
743
|
+
name
|
|
744
|
+
});
|
|
745
|
+
spinner.text = "Downloading template files...";
|
|
746
|
+
await mkdir4(projectDir, { recursive: true });
|
|
747
|
+
await pullFilesFromSandbox(result.id, projectDir);
|
|
748
|
+
spinner.text = "Setting up project config...";
|
|
749
|
+
const configDir = join4(projectDir, PROJECT_CONFIG_DIR);
|
|
750
|
+
const configPath = join4(configDir, PROJECT_CONFIG_FILE);
|
|
751
|
+
await mkdir4(configDir, { recursive: true });
|
|
752
|
+
const projectConfig = {
|
|
753
|
+
mcpId: result.id,
|
|
754
|
+
defaults: {
|
|
755
|
+
model: "claude-sonnet-4-20250514",
|
|
756
|
+
maxSteps: 10
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
await writeFile4(
|
|
760
|
+
configPath,
|
|
761
|
+
JSON.stringify(projectConfig, null, " "),
|
|
762
|
+
"utf-8"
|
|
763
|
+
);
|
|
764
|
+
spinner.succeed("MCP project created");
|
|
765
|
+
if (json) {
|
|
766
|
+
formatOutput(
|
|
767
|
+
{
|
|
768
|
+
success: true,
|
|
769
|
+
projectDir,
|
|
770
|
+
mcpId: result.id,
|
|
771
|
+
sandboxId: result.sandboxId,
|
|
772
|
+
previewUrl: result.previewUrl
|
|
773
|
+
},
|
|
774
|
+
true
|
|
367
775
|
);
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
776
|
+
} else {
|
|
777
|
+
console.log();
|
|
778
|
+
formatSuccess(`MCP project "${name}" created!`, false);
|
|
779
|
+
console.log();
|
|
780
|
+
console.log(` Project: ${projectDir}`);
|
|
781
|
+
console.log(` MCP ID: ${result.id}`);
|
|
782
|
+
console.log(` Preview URL: ${result.previewUrl}`);
|
|
783
|
+
console.log();
|
|
784
|
+
console.log("Next steps:");
|
|
785
|
+
console.log(` cd ${name}`);
|
|
786
|
+
console.log(" waniwani push # Sync files to sandbox");
|
|
787
|
+
console.log(" waniwani dev # Watch mode with auto-sync");
|
|
788
|
+
console.log(' waniwani task "..." # Send tasks to Claude');
|
|
372
789
|
}
|
|
790
|
+
} catch (error) {
|
|
791
|
+
handleError(error, json);
|
|
792
|
+
process.exit(1);
|
|
373
793
|
}
|
|
374
|
-
};
|
|
375
|
-
var auth = new AuthManager();
|
|
794
|
+
});
|
|
376
795
|
|
|
377
796
|
// src/commands/login.ts
|
|
797
|
+
import { spawn } from "child_process";
|
|
798
|
+
import { createServer } from "http";
|
|
799
|
+
import chalk4 from "chalk";
|
|
800
|
+
import { Command as Command3 } from "commander";
|
|
801
|
+
import ora3 from "ora";
|
|
378
802
|
var CALLBACK_PORT = 54321;
|
|
379
803
|
var CALLBACK_URL = `http://localhost:${CALLBACK_PORT}/callback`;
|
|
380
804
|
var CLIENT_NAME = "waniwani-cli";
|
|
@@ -649,7 +1073,7 @@ async function exchangeCodeForToken(code, codeVerifier, clientId, resource) {
|
|
|
649
1073
|
}
|
|
650
1074
|
return response.json();
|
|
651
1075
|
}
|
|
652
|
-
var loginCommand = new
|
|
1076
|
+
var loginCommand = new Command3("login").description("Log in to WaniWani").option("--no-browser", "Don't open the browser automatically").action(async (options, command) => {
|
|
653
1077
|
const globalOptions = command.optsWithGlobals();
|
|
654
1078
|
const json = globalOptions.json ?? false;
|
|
655
1079
|
try {
|
|
@@ -661,14 +1085,14 @@ var loginCommand = new Command2("login").description("Log in to WaniWani").optio
|
|
|
661
1085
|
formatOutput({ alreadyLoggedIn: true, refreshed: true }, true);
|
|
662
1086
|
} else {
|
|
663
1087
|
console.log(
|
|
664
|
-
|
|
1088
|
+
chalk4.green("Session refreshed. You're still logged in.")
|
|
665
1089
|
);
|
|
666
1090
|
}
|
|
667
1091
|
return;
|
|
668
1092
|
}
|
|
669
1093
|
if (!json) {
|
|
670
1094
|
console.log(
|
|
671
|
-
|
|
1095
|
+
chalk4.yellow("Session expired. Starting new login flow...")
|
|
672
1096
|
);
|
|
673
1097
|
}
|
|
674
1098
|
await auth.clear();
|
|
@@ -677,7 +1101,7 @@ var loginCommand = new Command2("login").description("Log in to WaniWani").optio
|
|
|
677
1101
|
formatOutput({ alreadyLoggedIn: true }, true);
|
|
678
1102
|
} else {
|
|
679
1103
|
console.log(
|
|
680
|
-
|
|
1104
|
+
chalk4.yellow(
|
|
681
1105
|
"Already logged in. Use 'waniwani logout' to log out first."
|
|
682
1106
|
)
|
|
683
1107
|
);
|
|
@@ -686,9 +1110,9 @@ var loginCommand = new Command2("login").description("Log in to WaniWani").optio
|
|
|
686
1110
|
}
|
|
687
1111
|
}
|
|
688
1112
|
if (!json) {
|
|
689
|
-
console.log(
|
|
1113
|
+
console.log(chalk4.bold("\nWaniWani CLI Login\n"));
|
|
690
1114
|
}
|
|
691
|
-
const spinner =
|
|
1115
|
+
const spinner = ora3("Registering client...").start();
|
|
692
1116
|
const { client_id: clientId } = await registerClient();
|
|
693
1117
|
spinner.text = "Preparing authentication...";
|
|
694
1118
|
const codeVerifier = generateCodeVerifier();
|
|
@@ -708,7 +1132,7 @@ var loginCommand = new Command2("login").description("Log in to WaniWani").optio
|
|
|
708
1132
|
console.log("Opening browser for authentication...\n");
|
|
709
1133
|
console.log(`If the browser doesn't open, visit:
|
|
710
1134
|
`);
|
|
711
|
-
console.log(
|
|
1135
|
+
console.log(chalk4.cyan(` ${authUrl.toString()}`));
|
|
712
1136
|
console.log();
|
|
713
1137
|
}
|
|
714
1138
|
const callbackPromise = waitForCallback(state);
|
|
@@ -754,8 +1178,8 @@ var loginCommand = new Command2("login").description("Log in to WaniWani").optio
|
|
|
754
1178
|
});
|
|
755
1179
|
|
|
756
1180
|
// src/commands/logout.ts
|
|
757
|
-
import { Command as
|
|
758
|
-
var logoutCommand = new
|
|
1181
|
+
import { Command as Command4 } from "commander";
|
|
1182
|
+
var logoutCommand = new Command4("logout").description("Log out from WaniWani").action(async (_, command) => {
|
|
759
1183
|
const globalOptions = command.optsWithGlobals();
|
|
760
1184
|
const json = globalOptions.json ?? false;
|
|
761
1185
|
try {
|
|
@@ -782,134 +1206,9 @@ var logoutCommand = new Command3("logout").description("Log out from WaniWani").
|
|
|
782
1206
|
// src/commands/mcp/index.ts
|
|
783
1207
|
import { Command as Command19 } from "commander";
|
|
784
1208
|
|
|
785
|
-
// src/commands/mcp/create.ts
|
|
786
|
-
import { Command as Command4 } from "commander";
|
|
787
|
-
import ora2 from "ora";
|
|
788
|
-
|
|
789
|
-
// src/lib/api.ts
|
|
790
|
-
var ApiError = class extends CLIError {
|
|
791
|
-
constructor(message, code, statusCode, details) {
|
|
792
|
-
super(message, code, details);
|
|
793
|
-
this.statusCode = statusCode;
|
|
794
|
-
this.name = "ApiError";
|
|
795
|
-
}
|
|
796
|
-
};
|
|
797
|
-
async function request(method, path, options) {
|
|
798
|
-
const {
|
|
799
|
-
body,
|
|
800
|
-
requireAuth = true,
|
|
801
|
-
headers: extraHeaders = {}
|
|
802
|
-
} = options || {};
|
|
803
|
-
const headers = {
|
|
804
|
-
"Content-Type": "application/json",
|
|
805
|
-
...extraHeaders
|
|
806
|
-
};
|
|
807
|
-
if (requireAuth) {
|
|
808
|
-
const token = await auth.getAccessToken();
|
|
809
|
-
if (!token) {
|
|
810
|
-
throw new AuthError(
|
|
811
|
-
"Not logged in. Run 'waniwani login' to authenticate."
|
|
812
|
-
);
|
|
813
|
-
}
|
|
814
|
-
headers.Authorization = `Bearer ${token}`;
|
|
815
|
-
}
|
|
816
|
-
const baseUrl = await config.getApiUrl();
|
|
817
|
-
const url = `${baseUrl}${path}`;
|
|
818
|
-
const response = await fetch(url, {
|
|
819
|
-
method,
|
|
820
|
-
headers,
|
|
821
|
-
body: body ? JSON.stringify(body) : void 0
|
|
822
|
-
});
|
|
823
|
-
if (response.status === 204) {
|
|
824
|
-
return void 0;
|
|
825
|
-
}
|
|
826
|
-
let data;
|
|
827
|
-
let rawBody;
|
|
828
|
-
try {
|
|
829
|
-
rawBody = await response.text();
|
|
830
|
-
data = JSON.parse(rawBody);
|
|
831
|
-
} catch {
|
|
832
|
-
throw new ApiError(
|
|
833
|
-
rawBody || `Request failed with status ${response.status}`,
|
|
834
|
-
"API_ERROR",
|
|
835
|
-
response.status,
|
|
836
|
-
{ statusText: response.statusText }
|
|
837
|
-
);
|
|
838
|
-
}
|
|
839
|
-
if (!response.ok || data.error) {
|
|
840
|
-
const errorMessage = data.error?.message || data.message || data.error || rawBody || `Request failed with status ${response.status}`;
|
|
841
|
-
const errorCode = data.error?.code || data.code || "API_ERROR";
|
|
842
|
-
const errorDetails = {
|
|
843
|
-
...data.error?.details,
|
|
844
|
-
statusText: response.statusText,
|
|
845
|
-
...data.error ? {} : { rawResponse: data }
|
|
846
|
-
};
|
|
847
|
-
const error = {
|
|
848
|
-
code: errorCode,
|
|
849
|
-
message: errorMessage,
|
|
850
|
-
details: errorDetails
|
|
851
|
-
};
|
|
852
|
-
if (response.status === 401) {
|
|
853
|
-
const refreshed = await auth.tryRefreshToken();
|
|
854
|
-
if (refreshed) {
|
|
855
|
-
return request(method, path, options);
|
|
856
|
-
}
|
|
857
|
-
throw new AuthError(
|
|
858
|
-
"Session expired. Run 'waniwani login' to re-authenticate."
|
|
859
|
-
);
|
|
860
|
-
}
|
|
861
|
-
throw new ApiError(
|
|
862
|
-
error.message,
|
|
863
|
-
error.code,
|
|
864
|
-
response.status,
|
|
865
|
-
error.details
|
|
866
|
-
);
|
|
867
|
-
}
|
|
868
|
-
return data.data;
|
|
869
|
-
}
|
|
870
|
-
var api = {
|
|
871
|
-
get: (path, options) => request("GET", path, options),
|
|
872
|
-
post: (path, body, options) => request("POST", path, { body, ...options }),
|
|
873
|
-
delete: (path, options) => request("DELETE", path, options),
|
|
874
|
-
getBaseUrl: () => config.getApiUrl()
|
|
875
|
-
};
|
|
876
|
-
|
|
877
|
-
// src/commands/mcp/create.ts
|
|
878
|
-
var createCommand = new Command4("create").description("Create a new MCP sandbox from template").argument("<name>", "Name for the MCP project").option("--global", "Save to global config instead of project config").action(async (name, options, command) => {
|
|
879
|
-
const globalOptions = command.optsWithGlobals();
|
|
880
|
-
const json = globalOptions.json ?? false;
|
|
881
|
-
try {
|
|
882
|
-
const spinner = ora2("Creating MCP sandbox...").start();
|
|
883
|
-
const result = await api.post("/api/mcp/sandboxes", {
|
|
884
|
-
name
|
|
885
|
-
});
|
|
886
|
-
spinner.succeed("MCP sandbox created");
|
|
887
|
-
const cfg = options.global ? globalConfig : config;
|
|
888
|
-
await cfg.setMcpId(result.id);
|
|
889
|
-
if (json) {
|
|
890
|
-
formatOutput({ ...result, scope: cfg.scope }, true);
|
|
891
|
-
} else {
|
|
892
|
-
console.log();
|
|
893
|
-
formatSuccess(`MCP sandbox "${name}" created! (${cfg.scope})`, false);
|
|
894
|
-
console.log();
|
|
895
|
-
console.log(` MCP ID: ${result.id}`);
|
|
896
|
-
console.log(` Sandbox ID: ${result.sandboxId}`);
|
|
897
|
-
console.log(` Preview URL: ${result.previewUrl}`);
|
|
898
|
-
console.log();
|
|
899
|
-
console.log(`Next steps:`);
|
|
900
|
-
console.log(` waniwani task "Add a tool that does X"`);
|
|
901
|
-
console.log(` waniwani mcp test`);
|
|
902
|
-
console.log(` waniwani mcp deploy`);
|
|
903
|
-
}
|
|
904
|
-
} catch (error) {
|
|
905
|
-
handleError(error, json);
|
|
906
|
-
process.exit(1);
|
|
907
|
-
}
|
|
908
|
-
});
|
|
909
|
-
|
|
910
1209
|
// src/commands/mcp/delete.ts
|
|
911
1210
|
import { Command as Command5 } from "commander";
|
|
912
|
-
import
|
|
1211
|
+
import ora4 from "ora";
|
|
913
1212
|
var deleteCommand = new Command5("delete").description("Delete the MCP sandbox").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
914
1213
|
const globalOptions = command.optsWithGlobals();
|
|
915
1214
|
const json = globalOptions.json ?? false;
|
|
@@ -921,7 +1220,7 @@ var deleteCommand = new Command5("delete").description("Delete the MCP sandbox")
|
|
|
921
1220
|
throw new McpError("No active MCP. Use --mcp-id to specify one.");
|
|
922
1221
|
}
|
|
923
1222
|
}
|
|
924
|
-
const spinner =
|
|
1223
|
+
const spinner = ora4("Deleting MCP sandbox...").start();
|
|
925
1224
|
await api.delete(`/api/mcp/sandboxes/${mcpId}`);
|
|
926
1225
|
spinner.succeed("MCP sandbox deleted");
|
|
927
1226
|
if (await config.getMcpId() === mcpId) {
|
|
@@ -940,7 +1239,7 @@ var deleteCommand = new Command5("delete").description("Delete the MCP sandbox")
|
|
|
940
1239
|
|
|
941
1240
|
// src/commands/mcp/deploy.ts
|
|
942
1241
|
import { Command as Command6 } from "commander";
|
|
943
|
-
import
|
|
1242
|
+
import ora5 from "ora";
|
|
944
1243
|
var deployCommand = new Command6("deploy").description("Deploy MCP server to GitHub + Vercel from sandbox").option("--repo <name>", "GitHub repository name").option("--org <name>", "GitHub organization").option("--private", "Create private repository").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
945
1244
|
const globalOptions = command.optsWithGlobals();
|
|
946
1245
|
const json = globalOptions.json ?? false;
|
|
@@ -954,7 +1253,7 @@ var deployCommand = new Command6("deploy").description("Deploy MCP server to Git
|
|
|
954
1253
|
);
|
|
955
1254
|
}
|
|
956
1255
|
}
|
|
957
|
-
const spinner =
|
|
1256
|
+
const spinner = ora5("Deploying to GitHub...").start();
|
|
958
1257
|
const result = await api.post(
|
|
959
1258
|
`/api/admin/mcps/${mcpId}/deploy`,
|
|
960
1259
|
{
|
|
@@ -989,9 +1288,9 @@ var deployCommand = new Command6("deploy").description("Deploy MCP server to Git
|
|
|
989
1288
|
import { Command as Command10 } from "commander";
|
|
990
1289
|
|
|
991
1290
|
// src/commands/mcp/file/list.ts
|
|
992
|
-
import
|
|
1291
|
+
import chalk5 from "chalk";
|
|
993
1292
|
import { Command as Command7 } from "commander";
|
|
994
|
-
import
|
|
1293
|
+
import ora6 from "ora";
|
|
995
1294
|
var listCommand = new Command7("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) => {
|
|
996
1295
|
const globalOptions = command.optsWithGlobals();
|
|
997
1296
|
const json = globalOptions.json ?? false;
|
|
@@ -1005,7 +1304,7 @@ var listCommand = new Command7("list").description("List files in the MCP sandbo
|
|
|
1005
1304
|
);
|
|
1006
1305
|
}
|
|
1007
1306
|
}
|
|
1008
|
-
const spinner =
|
|
1307
|
+
const spinner = ora6(`Listing ${path}...`).start();
|
|
1009
1308
|
const result = await api.get(
|
|
1010
1309
|
`/api/mcp/sandboxes/${mcpId}/files/list?path=${encodeURIComponent(path)}`
|
|
1011
1310
|
);
|
|
@@ -1013,15 +1312,15 @@ var listCommand = new Command7("list").description("List files in the MCP sandbo
|
|
|
1013
1312
|
if (json) {
|
|
1014
1313
|
formatOutput(result, true);
|
|
1015
1314
|
} else {
|
|
1016
|
-
console.log(
|
|
1315
|
+
console.log(chalk5.bold(`
|
|
1017
1316
|
Directory: ${result.path}
|
|
1018
1317
|
`));
|
|
1019
1318
|
if (result.entries.length === 0) {
|
|
1020
1319
|
console.log(" (empty)");
|
|
1021
1320
|
} else {
|
|
1022
1321
|
const rows = result.entries.map((entry) => {
|
|
1023
|
-
const name = entry.type === "directory" ?
|
|
1024
|
-
const size = entry.type === "directory" ?
|
|
1322
|
+
const name = entry.type === "directory" ? chalk5.blue(`${entry.name}/`) : entry.name;
|
|
1323
|
+
const size = entry.type === "directory" ? chalk5.gray("<dir>") : formatSize(entry.size);
|
|
1025
1324
|
return [name, size];
|
|
1026
1325
|
});
|
|
1027
1326
|
formatTable(["Name", "Size"], rows, false);
|
|
@@ -1041,9 +1340,9 @@ function formatSize(bytes) {
|
|
|
1041
1340
|
}
|
|
1042
1341
|
|
|
1043
1342
|
// src/commands/mcp/file/read.ts
|
|
1044
|
-
import { writeFile as
|
|
1343
|
+
import { writeFile as writeFile5 } from "fs/promises";
|
|
1045
1344
|
import { Command as Command8 } from "commander";
|
|
1046
|
-
import
|
|
1345
|
+
import ora7 from "ora";
|
|
1047
1346
|
var readCommand = new Command8("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) => {
|
|
1048
1347
|
const globalOptions = command.optsWithGlobals();
|
|
1049
1348
|
const json = globalOptions.json ?? false;
|
|
@@ -1058,7 +1357,7 @@ var readCommand = new Command8("read").description("Read a file from the MCP san
|
|
|
1058
1357
|
}
|
|
1059
1358
|
}
|
|
1060
1359
|
const encoding = options.base64 ? "base64" : "utf8";
|
|
1061
|
-
const spinner =
|
|
1360
|
+
const spinner = ora7(`Reading ${path}...`).start();
|
|
1062
1361
|
const result = await api.get(
|
|
1063
1362
|
`/api/mcp/sandboxes/${mcpId}/files?path=${encodeURIComponent(path)}&encoding=${encoding}`
|
|
1064
1363
|
);
|
|
@@ -1068,7 +1367,7 @@ var readCommand = new Command8("read").description("Read a file from the MCP san
|
|
|
1068
1367
|
}
|
|
1069
1368
|
if (options.output) {
|
|
1070
1369
|
const buffer = result.encoding === "base64" ? Buffer.from(result.content, "base64") : Buffer.from(result.content, "utf8");
|
|
1071
|
-
await
|
|
1370
|
+
await writeFile5(options.output, buffer);
|
|
1072
1371
|
if (json) {
|
|
1073
1372
|
formatOutput({ path, savedTo: options.output }, true);
|
|
1074
1373
|
} else {
|
|
@@ -1089,9 +1388,9 @@ var readCommand = new Command8("read").description("Read a file from the MCP san
|
|
|
1089
1388
|
});
|
|
1090
1389
|
|
|
1091
1390
|
// src/commands/mcp/file/write.ts
|
|
1092
|
-
import { readFile as
|
|
1391
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
1093
1392
|
import { Command as Command9 } from "commander";
|
|
1094
|
-
import
|
|
1393
|
+
import ora8 from "ora";
|
|
1095
1394
|
var writeCommand = new Command9("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) => {
|
|
1096
1395
|
const globalOptions = command.optsWithGlobals();
|
|
1097
1396
|
const json = globalOptions.json ?? false;
|
|
@@ -1113,7 +1412,7 @@ var writeCommand = new Command9("write").description("Write a file to the MCP sa
|
|
|
1113
1412
|
encoding = "base64";
|
|
1114
1413
|
}
|
|
1115
1414
|
} else if (options.file) {
|
|
1116
|
-
const fileBuffer = await
|
|
1415
|
+
const fileBuffer = await readFile4(options.file);
|
|
1117
1416
|
if (options.base64) {
|
|
1118
1417
|
content = fileBuffer.toString("base64");
|
|
1119
1418
|
encoding = "base64";
|
|
@@ -1126,7 +1425,7 @@ var writeCommand = new Command9("write").description("Write a file to the MCP sa
|
|
|
1126
1425
|
"MISSING_CONTENT"
|
|
1127
1426
|
);
|
|
1128
1427
|
}
|
|
1129
|
-
const spinner =
|
|
1428
|
+
const spinner = ora8(`Writing ${path}...`).start();
|
|
1130
1429
|
const result = await api.post(
|
|
1131
1430
|
`/api/mcp/sandboxes/${mcpId}/files`,
|
|
1132
1431
|
{
|
|
@@ -1149,14 +1448,14 @@ var writeCommand = new Command9("write").description("Write a file to the MCP sa
|
|
|
1149
1448
|
var fileCommand = new Command10("file").description("File operations in MCP sandbox").addCommand(readCommand).addCommand(writeCommand).addCommand(listCommand);
|
|
1150
1449
|
|
|
1151
1450
|
// src/commands/mcp/list.ts
|
|
1152
|
-
import
|
|
1451
|
+
import chalk6 from "chalk";
|
|
1153
1452
|
import { Command as Command11 } from "commander";
|
|
1154
|
-
import
|
|
1453
|
+
import ora9 from "ora";
|
|
1155
1454
|
var listCommand2 = new Command11("list").description("List all MCPs in your organization").option("--all", "Include stopped/expired MCPs").action(async (options, command) => {
|
|
1156
1455
|
const globalOptions = command.optsWithGlobals();
|
|
1157
1456
|
const json = globalOptions.json ?? false;
|
|
1158
1457
|
try {
|
|
1159
|
-
const spinner =
|
|
1458
|
+
const spinner = ora9("Fetching MCPs...").start();
|
|
1160
1459
|
const mcps = await api.get(
|
|
1161
1460
|
`/api/mcp/sandboxes${options.all ? "?all=true" : ""}`
|
|
1162
1461
|
);
|
|
@@ -1179,12 +1478,12 @@ var listCommand2 = new Command11("list").description("List all MCPs in your orga
|
|
|
1179
1478
|
console.log("\nCreate a new MCP sandbox: waniwani mcp create <name>");
|
|
1180
1479
|
return;
|
|
1181
1480
|
}
|
|
1182
|
-
console.log(
|
|
1481
|
+
console.log(chalk6.bold("\nMCPs:\n"));
|
|
1183
1482
|
const rows = mcps.map((m) => {
|
|
1184
1483
|
const isActive = m.id === activeMcpId;
|
|
1185
|
-
const statusColor = m.status === "active" ?
|
|
1484
|
+
const statusColor = m.status === "active" ? chalk6.green : m.status === "stopped" ? chalk6.red : chalk6.yellow;
|
|
1186
1485
|
return [
|
|
1187
|
-
isActive ?
|
|
1486
|
+
isActive ? chalk6.cyan(`* ${m.id.slice(0, 8)}`) : ` ${m.id.slice(0, 8)}`,
|
|
1188
1487
|
m.name,
|
|
1189
1488
|
statusColor(m.status),
|
|
1190
1489
|
m.previewUrl,
|
|
@@ -1198,7 +1497,7 @@ var listCommand2 = new Command11("list").description("List all MCPs in your orga
|
|
|
1198
1497
|
);
|
|
1199
1498
|
console.log();
|
|
1200
1499
|
if (activeMcpId) {
|
|
1201
|
-
console.log(`Active MCP: ${
|
|
1500
|
+
console.log(`Active MCP: ${chalk6.cyan(activeMcpId.slice(0, 8))}`);
|
|
1202
1501
|
}
|
|
1203
1502
|
console.log("\nSelect an MCP: waniwani mcp use <name>");
|
|
1204
1503
|
}
|
|
@@ -1209,9 +1508,9 @@ var listCommand2 = new Command11("list").description("List all MCPs in your orga
|
|
|
1209
1508
|
});
|
|
1210
1509
|
|
|
1211
1510
|
// src/commands/mcp/logs.ts
|
|
1212
|
-
import
|
|
1511
|
+
import chalk7 from "chalk";
|
|
1213
1512
|
import { Command as Command12 } from "commander";
|
|
1214
|
-
import
|
|
1513
|
+
import ora10 from "ora";
|
|
1215
1514
|
var logsCommand = new Command12("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) => {
|
|
1216
1515
|
const globalOptions = command.optsWithGlobals();
|
|
1217
1516
|
const json = globalOptions.json ?? false;
|
|
@@ -1243,7 +1542,7 @@ var logsCommand = new Command12("logs").description("Stream logs from the MCP se
|
|
|
1243
1542
|
}
|
|
1244
1543
|
let cmdId = cmdIdArg;
|
|
1245
1544
|
if (!cmdId) {
|
|
1246
|
-
const spinner =
|
|
1545
|
+
const spinner = ora10("Getting server status...").start();
|
|
1247
1546
|
const status = await api.post(
|
|
1248
1547
|
`/api/mcp/sandboxes/${mcpId}/server`,
|
|
1249
1548
|
{ action: "status" }
|
|
@@ -1260,8 +1559,8 @@ var logsCommand = new Command12("logs").description("Stream logs from the MCP se
|
|
|
1260
1559
|
const streamParam = options.follow ? "?stream=true" : "";
|
|
1261
1560
|
const url = `${baseUrl}/api/mcp/sandboxes/${mcpId}/commands/${cmdId}${streamParam}`;
|
|
1262
1561
|
if (!json) {
|
|
1263
|
-
console.log(
|
|
1264
|
-
console.log(
|
|
1562
|
+
console.log(chalk7.gray(`Streaming logs for command ${cmdId}...`));
|
|
1563
|
+
console.log(chalk7.gray("Press Ctrl+C to stop\n"));
|
|
1265
1564
|
}
|
|
1266
1565
|
const response = await fetch(url, {
|
|
1267
1566
|
method: "GET",
|
|
@@ -1285,10 +1584,10 @@ var logsCommand = new Command12("logs").description("Stream logs from the MCP se
|
|
|
1285
1584
|
process.stdout.write(data.stdout);
|
|
1286
1585
|
}
|
|
1287
1586
|
if (data.stderr) {
|
|
1288
|
-
process.stderr.write(
|
|
1587
|
+
process.stderr.write(chalk7.red(data.stderr));
|
|
1289
1588
|
}
|
|
1290
1589
|
if (data.exitCode !== void 0) {
|
|
1291
|
-
console.log(
|
|
1590
|
+
console.log(chalk7.gray(`
|
|
1292
1591
|
Exit code: ${data.exitCode}`));
|
|
1293
1592
|
}
|
|
1294
1593
|
}
|
|
@@ -1327,18 +1626,18 @@ Exit code: ${data.exitCode}`));
|
|
|
1327
1626
|
if (event.stream === "stdout") {
|
|
1328
1627
|
process.stdout.write(event.data);
|
|
1329
1628
|
} else if (event.stream === "stderr") {
|
|
1330
|
-
process.stderr.write(
|
|
1629
|
+
process.stderr.write(chalk7.red(event.data));
|
|
1331
1630
|
}
|
|
1332
1631
|
}
|
|
1333
1632
|
if (event.exitCode !== void 0) {
|
|
1334
|
-
const exitColor = event.exitCode === 0 ?
|
|
1633
|
+
const exitColor = event.exitCode === 0 ? chalk7.green : chalk7.red;
|
|
1335
1634
|
console.log(
|
|
1336
1635
|
exitColor(`
|
|
1337
1636
|
Process exited with code ${event.exitCode}`)
|
|
1338
1637
|
);
|
|
1339
1638
|
}
|
|
1340
1639
|
if (event.error) {
|
|
1341
|
-
console.error(
|
|
1640
|
+
console.error(chalk7.red(`
|
|
1342
1641
|
Error: ${event.error}`));
|
|
1343
1642
|
}
|
|
1344
1643
|
} catch {
|
|
@@ -1359,9 +1658,9 @@ Error: ${event.error}`));
|
|
|
1359
1658
|
});
|
|
1360
1659
|
|
|
1361
1660
|
// src/commands/mcp/run-command.ts
|
|
1362
|
-
import
|
|
1661
|
+
import chalk8 from "chalk";
|
|
1363
1662
|
import { Command as Command13 } from "commander";
|
|
1364
|
-
import
|
|
1663
|
+
import ora11 from "ora";
|
|
1365
1664
|
var runCommandCommand = new Command13("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(
|
|
1366
1665
|
"--timeout <ms>",
|
|
1367
1666
|
"Command timeout in milliseconds (default: 30000, max: 300000)"
|
|
@@ -1379,7 +1678,7 @@ var runCommandCommand = new Command13("run-command").description("Run a command
|
|
|
1379
1678
|
}
|
|
1380
1679
|
}
|
|
1381
1680
|
const timeout = options.timeout ? Number.parseInt(options.timeout, 10) : void 0;
|
|
1382
|
-
const spinner =
|
|
1681
|
+
const spinner = ora11(`Running: ${cmd} ${args.join(" ")}`.trim()).start();
|
|
1383
1682
|
const result = await api.post(
|
|
1384
1683
|
`/api/mcp/sandboxes/${mcpId}/commands`,
|
|
1385
1684
|
{
|
|
@@ -1394,7 +1693,7 @@ var runCommandCommand = new Command13("run-command").description("Run a command
|
|
|
1394
1693
|
formatOutput(result, true);
|
|
1395
1694
|
} else {
|
|
1396
1695
|
const cmdLine = [cmd, ...args].join(" ");
|
|
1397
|
-
console.log(
|
|
1696
|
+
console.log(chalk8.gray(`$ ${cmdLine}`));
|
|
1398
1697
|
console.log();
|
|
1399
1698
|
if (result.stdout) {
|
|
1400
1699
|
process.stdout.write(result.stdout);
|
|
@@ -1403,16 +1702,16 @@ var runCommandCommand = new Command13("run-command").description("Run a command
|
|
|
1403
1702
|
}
|
|
1404
1703
|
}
|
|
1405
1704
|
if (result.stderr) {
|
|
1406
|
-
process.stderr.write(
|
|
1705
|
+
process.stderr.write(chalk8.red(result.stderr));
|
|
1407
1706
|
if (!result.stderr.endsWith("\n")) {
|
|
1408
1707
|
process.stderr.write("\n");
|
|
1409
1708
|
}
|
|
1410
1709
|
}
|
|
1411
1710
|
console.log();
|
|
1412
|
-
const exitColor = result.exitCode === 0 ?
|
|
1711
|
+
const exitColor = result.exitCode === 0 ? chalk8.green : chalk8.red;
|
|
1413
1712
|
console.log(
|
|
1414
1713
|
exitColor(`Exit code: ${result.exitCode}`),
|
|
1415
|
-
|
|
1714
|
+
chalk8.gray(`(${(result.duration / 1e3).toFixed(2)}s)`)
|
|
1416
1715
|
);
|
|
1417
1716
|
}
|
|
1418
1717
|
if (result.exitCode !== 0) {
|
|
@@ -1425,9 +1724,9 @@ var runCommandCommand = new Command13("run-command").description("Run a command
|
|
|
1425
1724
|
});
|
|
1426
1725
|
|
|
1427
1726
|
// src/commands/mcp/start.ts
|
|
1428
|
-
import
|
|
1727
|
+
import chalk9 from "chalk";
|
|
1429
1728
|
import { Command as Command14 } from "commander";
|
|
1430
|
-
import
|
|
1729
|
+
import ora12 from "ora";
|
|
1431
1730
|
var startCommand = new Command14("start").description("Start the MCP server (npm run dev)").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1432
1731
|
const globalOptions = command.optsWithGlobals();
|
|
1433
1732
|
const json = globalOptions.json ?? false;
|
|
@@ -1441,7 +1740,7 @@ var startCommand = new Command14("start").description("Start the MCP server (npm
|
|
|
1441
1740
|
);
|
|
1442
1741
|
}
|
|
1443
1742
|
}
|
|
1444
|
-
const spinner =
|
|
1743
|
+
const spinner = ora12("Starting MCP server...").start();
|
|
1445
1744
|
const result = await api.post(
|
|
1446
1745
|
`/api/mcp/sandboxes/${mcpId}/server`,
|
|
1447
1746
|
{ action: "start" }
|
|
@@ -1454,13 +1753,13 @@ var startCommand = new Command14("start").description("Start the MCP server (npm
|
|
|
1454
1753
|
formatList(
|
|
1455
1754
|
[
|
|
1456
1755
|
{ label: "Command ID", value: result.cmdId },
|
|
1457
|
-
{ label: "Preview URL", value:
|
|
1756
|
+
{ label: "Preview URL", value: chalk9.cyan(result.previewUrl) }
|
|
1458
1757
|
],
|
|
1459
1758
|
false
|
|
1460
1759
|
);
|
|
1461
1760
|
console.log();
|
|
1462
1761
|
console.log(
|
|
1463
|
-
|
|
1762
|
+
chalk9.gray("Run 'waniwani mcp logs' to stream server output")
|
|
1464
1763
|
);
|
|
1465
1764
|
}
|
|
1466
1765
|
} catch (error) {
|
|
@@ -1470,9 +1769,9 @@ var startCommand = new Command14("start").description("Start the MCP server (npm
|
|
|
1470
1769
|
});
|
|
1471
1770
|
|
|
1472
1771
|
// src/commands/mcp/status.ts
|
|
1473
|
-
import
|
|
1772
|
+
import chalk10 from "chalk";
|
|
1474
1773
|
import { Command as Command15 } from "commander";
|
|
1475
|
-
import
|
|
1774
|
+
import ora13 from "ora";
|
|
1476
1775
|
var statusCommand = new Command15("status").description("Show current MCP sandbox status").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1477
1776
|
const globalOptions = command.optsWithGlobals();
|
|
1478
1777
|
const json = globalOptions.json ?? false;
|
|
@@ -1486,7 +1785,7 @@ var statusCommand = new Command15("status").description("Show current MCP sandbo
|
|
|
1486
1785
|
);
|
|
1487
1786
|
}
|
|
1488
1787
|
}
|
|
1489
|
-
const spinner =
|
|
1788
|
+
const spinner = ora13("Fetching MCP status...").start();
|
|
1490
1789
|
const [result, serverStatus] = await Promise.all([
|
|
1491
1790
|
api.get(`/api/mcp/sandboxes/${mcpId}`),
|
|
1492
1791
|
api.post(`/api/mcp/sandboxes/${mcpId}/server`, {
|
|
@@ -1501,9 +1800,9 @@ var statusCommand = new Command15("status").description("Show current MCP sandbo
|
|
|
1501
1800
|
if (json) {
|
|
1502
1801
|
formatOutput({ ...result, server: serverStatus }, true);
|
|
1503
1802
|
} else {
|
|
1504
|
-
const statusColor = result.status === "active" ?
|
|
1803
|
+
const statusColor = result.status === "active" ? chalk10.green : chalk10.red;
|
|
1505
1804
|
const serverRunning = serverStatus.running;
|
|
1506
|
-
const serverStatusColor = serverRunning ?
|
|
1805
|
+
const serverStatusColor = serverRunning ? chalk10.green : chalk10.yellow;
|
|
1507
1806
|
formatList(
|
|
1508
1807
|
[
|
|
1509
1808
|
{ label: "MCP ID", value: result.id },
|
|
@@ -1530,7 +1829,7 @@ var statusCommand = new Command15("status").description("Show current MCP sandbo
|
|
|
1530
1829
|
|
|
1531
1830
|
// src/commands/mcp/stop.ts
|
|
1532
1831
|
import { Command as Command16 } from "commander";
|
|
1533
|
-
import
|
|
1832
|
+
import ora14 from "ora";
|
|
1534
1833
|
var stopCommand = new Command16("stop").description("Stop the MCP server process").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1535
1834
|
const globalOptions = command.optsWithGlobals();
|
|
1536
1835
|
const json = globalOptions.json ?? false;
|
|
@@ -1544,7 +1843,7 @@ var stopCommand = new Command16("stop").description("Stop the MCP server process
|
|
|
1544
1843
|
);
|
|
1545
1844
|
}
|
|
1546
1845
|
}
|
|
1547
|
-
const spinner =
|
|
1846
|
+
const spinner = ora14("Stopping MCP server...").start();
|
|
1548
1847
|
const result = await api.post(
|
|
1549
1848
|
`/api/mcp/sandboxes/${mcpId}/server`,
|
|
1550
1849
|
{ action: "stop" }
|
|
@@ -1566,9 +1865,9 @@ var stopCommand = new Command16("stop").description("Stop the MCP server process
|
|
|
1566
1865
|
});
|
|
1567
1866
|
|
|
1568
1867
|
// src/commands/mcp/test.ts
|
|
1569
|
-
import
|
|
1868
|
+
import chalk11 from "chalk";
|
|
1570
1869
|
import { Command as Command17 } from "commander";
|
|
1571
|
-
import
|
|
1870
|
+
import ora15 from "ora";
|
|
1572
1871
|
var testCommand = new Command17("test").description("Test MCP tools via the sandbox").argument("[tool]", "Tool name to test (lists tools if omitted)").argument("[args...]", "JSON arguments for the tool").option("--mcp-id <id>", "Specific MCP ID").action(
|
|
1573
1872
|
async (tool, args, options, command) => {
|
|
1574
1873
|
const globalOptions = command.optsWithGlobals();
|
|
@@ -1584,7 +1883,7 @@ var testCommand = new Command17("test").description("Test MCP tools via the sand
|
|
|
1584
1883
|
}
|
|
1585
1884
|
}
|
|
1586
1885
|
if (!tool) {
|
|
1587
|
-
const spinner =
|
|
1886
|
+
const spinner = ora15("Fetching available tools...").start();
|
|
1588
1887
|
const result = await api.post(
|
|
1589
1888
|
`/api/mcp/sandboxes/${mcpId}/test`,
|
|
1590
1889
|
{ action: "list" }
|
|
@@ -1597,7 +1896,7 @@ var testCommand = new Command17("test").description("Test MCP tools via the sand
|
|
|
1597
1896
|
if (tools.length === 0) {
|
|
1598
1897
|
console.log("No tools available.");
|
|
1599
1898
|
} else {
|
|
1600
|
-
console.log(
|
|
1899
|
+
console.log(chalk11.bold("\nAvailable Tools:\n"));
|
|
1601
1900
|
formatTable(
|
|
1602
1901
|
["Name", "Description"],
|
|
1603
1902
|
tools.map((t) => [t.name, t.description || "No description"]),
|
|
@@ -1620,7 +1919,7 @@ Test a tool: waniwani mcp test <tool-name> '{"arg": "value"}'`
|
|
|
1620
1919
|
);
|
|
1621
1920
|
}
|
|
1622
1921
|
}
|
|
1623
|
-
const spinner =
|
|
1922
|
+
const spinner = ora15(`Calling tool "${tool}"...`).start();
|
|
1624
1923
|
const startTime = Date.now();
|
|
1625
1924
|
const result = await api.post(
|
|
1626
1925
|
`/api/mcp/sandboxes/${mcpId}/test`,
|
|
@@ -1641,11 +1940,11 @@ Test a tool: waniwani mcp test <tool-name> '{"arg": "value"}'`
|
|
|
1641
1940
|
if (json) {
|
|
1642
1941
|
formatOutput(output, true);
|
|
1643
1942
|
} else {
|
|
1644
|
-
console.log(
|
|
1645
|
-
console.log(
|
|
1646
|
-
console.log(
|
|
1647
|
-
console.log(
|
|
1648
|
-
console.log(
|
|
1943
|
+
console.log(chalk11.bold("\nTool Result:\n"));
|
|
1944
|
+
console.log(chalk11.gray("Tool:"), tool);
|
|
1945
|
+
console.log(chalk11.gray("Input:"), JSON.stringify(toolArgs));
|
|
1946
|
+
console.log(chalk11.gray("Duration:"), `${duration}ms`);
|
|
1947
|
+
console.log(chalk11.gray("Result:"));
|
|
1649
1948
|
console.log(JSON.stringify(result.result, null, 2));
|
|
1650
1949
|
}
|
|
1651
1950
|
}
|
|
@@ -1658,12 +1957,12 @@ Test a tool: waniwani mcp test <tool-name> '{"arg": "value"}'`
|
|
|
1658
1957
|
|
|
1659
1958
|
// src/commands/mcp/use.ts
|
|
1660
1959
|
import { Command as Command18 } from "commander";
|
|
1661
|
-
import
|
|
1960
|
+
import ora16 from "ora";
|
|
1662
1961
|
var useCommand = new Command18("use").description("Select an MCP to use for subsequent commands").argument("<name>", "Name of the MCP to use").option("--global", "Save to global config instead of project config").action(async (name, options, command) => {
|
|
1663
1962
|
const globalOptions = command.optsWithGlobals();
|
|
1664
1963
|
const json = globalOptions.json ?? false;
|
|
1665
1964
|
try {
|
|
1666
|
-
const spinner =
|
|
1965
|
+
const spinner = ora16("Fetching MCPs...").start();
|
|
1667
1966
|
const mcps = await api.get("/api/admin/mcps");
|
|
1668
1967
|
spinner.stop();
|
|
1669
1968
|
const mcp = mcps.find((m) => m.name === name);
|
|
@@ -1699,20 +1998,20 @@ var useCommand = new Command18("use").description("Select an MCP to use for subs
|
|
|
1699
1998
|
});
|
|
1700
1999
|
|
|
1701
2000
|
// src/commands/mcp/index.ts
|
|
1702
|
-
var mcpCommand = new Command19("mcp").description("MCP sandbox management commands").addCommand(
|
|
2001
|
+
var mcpCommand = new Command19("mcp").description("MCP sandbox management commands").addCommand(listCommand2).addCommand(useCommand).addCommand(statusCommand).addCommand(startCommand).addCommand(stopCommand).addCommand(logsCommand).addCommand(deleteCommand).addCommand(testCommand).addCommand(deployCommand).addCommand(fileCommand).addCommand(runCommandCommand);
|
|
1703
2002
|
|
|
1704
2003
|
// src/commands/org/index.ts
|
|
1705
2004
|
import { Command as Command22 } from "commander";
|
|
1706
2005
|
|
|
1707
2006
|
// src/commands/org/list.ts
|
|
1708
|
-
import
|
|
2007
|
+
import chalk12 from "chalk";
|
|
1709
2008
|
import { Command as Command20 } from "commander";
|
|
1710
|
-
import
|
|
2009
|
+
import ora17 from "ora";
|
|
1711
2010
|
var listCommand3 = new Command20("list").description("List your organizations").action(async (_, command) => {
|
|
1712
2011
|
const globalOptions = command.optsWithGlobals();
|
|
1713
2012
|
const json = globalOptions.json ?? false;
|
|
1714
2013
|
try {
|
|
1715
|
-
const spinner =
|
|
2014
|
+
const spinner = ora17("Fetching organizations...").start();
|
|
1716
2015
|
const result = await api.get("/api/oauth/orgs");
|
|
1717
2016
|
spinner.stop();
|
|
1718
2017
|
const { orgs, activeOrgId } = result;
|
|
@@ -1732,11 +2031,11 @@ var listCommand3 = new Command20("list").description("List your organizations").
|
|
|
1732
2031
|
console.log("No organizations found.");
|
|
1733
2032
|
return;
|
|
1734
2033
|
}
|
|
1735
|
-
console.log(
|
|
2034
|
+
console.log(chalk12.bold("\nOrganizations:\n"));
|
|
1736
2035
|
const rows = orgs.map((o) => {
|
|
1737
2036
|
const isActive = o.id === activeOrgId;
|
|
1738
2037
|
return [
|
|
1739
|
-
isActive ?
|
|
2038
|
+
isActive ? chalk12.cyan(`* ${o.name}`) : ` ${o.name}`,
|
|
1740
2039
|
o.slug,
|
|
1741
2040
|
o.role
|
|
1742
2041
|
];
|
|
@@ -1746,7 +2045,7 @@ var listCommand3 = new Command20("list").description("List your organizations").
|
|
|
1746
2045
|
if (activeOrgId) {
|
|
1747
2046
|
const activeOrg = orgs.find((o) => o.id === activeOrgId);
|
|
1748
2047
|
if (activeOrg) {
|
|
1749
|
-
console.log(`Active organization: ${
|
|
2048
|
+
console.log(`Active organization: ${chalk12.cyan(activeOrg.name)}`);
|
|
1750
2049
|
}
|
|
1751
2050
|
}
|
|
1752
2051
|
console.log("\nSwitch organization: waniwani org switch <name>");
|
|
@@ -1759,12 +2058,12 @@ var listCommand3 = new Command20("list").description("List your organizations").
|
|
|
1759
2058
|
|
|
1760
2059
|
// src/commands/org/switch.ts
|
|
1761
2060
|
import { Command as Command21 } from "commander";
|
|
1762
|
-
import
|
|
2061
|
+
import ora18 from "ora";
|
|
1763
2062
|
var switchCommand = new Command21("switch").description("Switch to a different organization").argument("<name>", "Name or slug of the organization to switch to").action(async (name, _, command) => {
|
|
1764
2063
|
const globalOptions = command.optsWithGlobals();
|
|
1765
2064
|
const json = globalOptions.json ?? false;
|
|
1766
2065
|
try {
|
|
1767
|
-
const spinner =
|
|
2066
|
+
const spinner = ora18("Fetching organizations...").start();
|
|
1768
2067
|
const { orgs } = await api.get("/api/oauth/orgs");
|
|
1769
2068
|
const org = orgs.find((o) => o.name === name || o.slug === name);
|
|
1770
2069
|
if (!org) {
|
|
@@ -1799,11 +2098,92 @@ var switchCommand = new Command21("switch").description("Switch to a different o
|
|
|
1799
2098
|
// src/commands/org/index.ts
|
|
1800
2099
|
var orgCommand = new Command22("org").description("Organization management commands").addCommand(listCommand3).addCommand(switchCommand);
|
|
1801
2100
|
|
|
1802
|
-
// src/commands/
|
|
1803
|
-
import
|
|
2101
|
+
// src/commands/push.ts
|
|
2102
|
+
import chalk13 from "chalk";
|
|
1804
2103
|
import { Command as Command23 } from "commander";
|
|
1805
|
-
import
|
|
1806
|
-
var
|
|
2104
|
+
import ora19 from "ora";
|
|
2105
|
+
var BATCH_SIZE2 = 50;
|
|
2106
|
+
var pushCommand = new Command23("push").description("Sync local files to MCP sandbox").option("--dry-run", "Show what would be synced without uploading").action(async (options, command) => {
|
|
2107
|
+
const globalOptions = command.optsWithGlobals();
|
|
2108
|
+
const json = globalOptions.json ?? false;
|
|
2109
|
+
try {
|
|
2110
|
+
const cwd = process.cwd();
|
|
2111
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
2112
|
+
if (!projectRoot) {
|
|
2113
|
+
throw new CLIError(
|
|
2114
|
+
"Not in a WaniWani project. Run 'waniwani init <name>' first.",
|
|
2115
|
+
"NOT_IN_PROJECT"
|
|
2116
|
+
);
|
|
2117
|
+
}
|
|
2118
|
+
const mcpId = await loadProjectMcpId(projectRoot);
|
|
2119
|
+
if (!mcpId) {
|
|
2120
|
+
throw new CLIError(
|
|
2121
|
+
"No MCP ID found in project config. Run 'waniwani init <name>' first.",
|
|
2122
|
+
"NO_MCP_ID"
|
|
2123
|
+
);
|
|
2124
|
+
}
|
|
2125
|
+
const spinner = ora19("Collecting files...").start();
|
|
2126
|
+
const files = await collectFiles(projectRoot);
|
|
2127
|
+
if (files.length === 0) {
|
|
2128
|
+
spinner.info("No files to sync");
|
|
2129
|
+
if (json) {
|
|
2130
|
+
formatOutput({ synced: 0, files: [] }, true);
|
|
2131
|
+
}
|
|
2132
|
+
return;
|
|
2133
|
+
}
|
|
2134
|
+
spinner.text = `Found ${files.length} files`;
|
|
2135
|
+
if (options.dryRun) {
|
|
2136
|
+
spinner.stop();
|
|
2137
|
+
console.log();
|
|
2138
|
+
console.log(chalk13.bold("Files that would be synced:"));
|
|
2139
|
+
for (const file of files) {
|
|
2140
|
+
console.log(` ${file.path}`);
|
|
2141
|
+
}
|
|
2142
|
+
console.log();
|
|
2143
|
+
console.log(`Total: ${files.length} files`);
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
const allWritten = [];
|
|
2147
|
+
const totalBatches = Math.ceil(files.length / BATCH_SIZE2);
|
|
2148
|
+
for (let i = 0; i < totalBatches; i++) {
|
|
2149
|
+
const batch = files.slice(i * BATCH_SIZE2, (i + 1) * BATCH_SIZE2);
|
|
2150
|
+
spinner.text = `Syncing files (${i + 1}/${totalBatches})...`;
|
|
2151
|
+
const result = await api.post(
|
|
2152
|
+
`/api/mcp/sandboxes/${mcpId}/files`,
|
|
2153
|
+
{
|
|
2154
|
+
files: batch.map((f) => ({
|
|
2155
|
+
path: f.path,
|
|
2156
|
+
content: f.content,
|
|
2157
|
+
encoding: f.encoding
|
|
2158
|
+
}))
|
|
2159
|
+
}
|
|
2160
|
+
);
|
|
2161
|
+
allWritten.push(...result.written);
|
|
2162
|
+
}
|
|
2163
|
+
spinner.succeed(`Synced ${allWritten.length} files`);
|
|
2164
|
+
if (json) {
|
|
2165
|
+
formatOutput(
|
|
2166
|
+
{
|
|
2167
|
+
synced: allWritten.length,
|
|
2168
|
+
files: allWritten
|
|
2169
|
+
},
|
|
2170
|
+
true
|
|
2171
|
+
);
|
|
2172
|
+
} else {
|
|
2173
|
+
console.log();
|
|
2174
|
+
formatSuccess(`${allWritten.length} files synced to sandbox`, false);
|
|
2175
|
+
}
|
|
2176
|
+
} catch (error) {
|
|
2177
|
+
handleError(error, json);
|
|
2178
|
+
process.exit(1);
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
|
|
2182
|
+
// src/commands/task.ts
|
|
2183
|
+
import chalk14 from "chalk";
|
|
2184
|
+
import { Command as Command24 } from "commander";
|
|
2185
|
+
import ora20 from "ora";
|
|
2186
|
+
var taskCommand = new Command24("task").description("Send a task to Claude running in the sandbox").argument("<prompt>", "Task description/prompt").option("--mcp-id <id>", "Specific MCP ID").option("--model <model>", "Claude model to use").option("--max-steps <n>", "Maximum tool use steps").action(async (prompt, options, command) => {
|
|
1807
2187
|
const globalOptions = command.optsWithGlobals();
|
|
1808
2188
|
const json = globalOptions.json ?? false;
|
|
1809
2189
|
try {
|
|
@@ -1827,10 +2207,10 @@ var taskCommand = new Command23("task").description("Send a task to Claude runni
|
|
|
1827
2207
|
const maxSteps = options.maxSteps ? Number.parseInt(options.maxSteps, 10) : defaults.maxSteps;
|
|
1828
2208
|
if (!json) {
|
|
1829
2209
|
console.log();
|
|
1830
|
-
console.log(
|
|
2210
|
+
console.log(chalk14.bold("Task:"), prompt);
|
|
1831
2211
|
console.log();
|
|
1832
2212
|
}
|
|
1833
|
-
const spinner =
|
|
2213
|
+
const spinner = ora20("Starting task...").start();
|
|
1834
2214
|
const baseUrl = await api.getBaseUrl();
|
|
1835
2215
|
const response = await fetch(
|
|
1836
2216
|
`${baseUrl}/api/mcp/sandboxes/${mcpId}/task`,
|
|
@@ -1884,7 +2264,7 @@ var taskCommand = new Command23("task").description("Send a task to Claude runni
|
|
|
1884
2264
|
const event = parsed;
|
|
1885
2265
|
steps.push({ type: "text", text: event.content });
|
|
1886
2266
|
if (!json && event.content) {
|
|
1887
|
-
console.log(
|
|
2267
|
+
console.log(chalk14.white(event.content));
|
|
1888
2268
|
}
|
|
1889
2269
|
} else if (parsed.type === "tool_call") {
|
|
1890
2270
|
const event = parsed;
|
|
@@ -1895,24 +2275,24 @@ var taskCommand = new Command23("task").description("Send a task to Claude runni
|
|
|
1895
2275
|
output: event.output
|
|
1896
2276
|
});
|
|
1897
2277
|
if (!json) {
|
|
1898
|
-
console.log(
|
|
2278
|
+
console.log(chalk14.cyan(`> Using tool: ${event.tool}`));
|
|
1899
2279
|
if (event.input?.command) {
|
|
1900
|
-
console.log(
|
|
2280
|
+
console.log(chalk14.gray(` $ ${event.input.command}`));
|
|
1901
2281
|
}
|
|
1902
2282
|
if (event.output) {
|
|
1903
2283
|
const outputLines = event.output.split("\n");
|
|
1904
2284
|
if (outputLines.length > 10) {
|
|
1905
2285
|
console.log(
|
|
1906
|
-
|
|
2286
|
+
chalk14.gray(outputLines.slice(0, 5).join("\n"))
|
|
1907
2287
|
);
|
|
1908
2288
|
console.log(
|
|
1909
|
-
|
|
2289
|
+
chalk14.gray(
|
|
1910
2290
|
` ... (${outputLines.length - 10} more lines)`
|
|
1911
2291
|
)
|
|
1912
2292
|
);
|
|
1913
|
-
console.log(
|
|
2293
|
+
console.log(chalk14.gray(outputLines.slice(-5).join("\n")));
|
|
1914
2294
|
} else {
|
|
1915
|
-
console.log(
|
|
2295
|
+
console.log(chalk14.gray(event.output));
|
|
1916
2296
|
}
|
|
1917
2297
|
}
|
|
1918
2298
|
console.log();
|
|
@@ -1939,12 +2319,12 @@ var taskCommand = new Command23("task").description("Send a task to Claude runni
|
|
|
1939
2319
|
} else {
|
|
1940
2320
|
console.log();
|
|
1941
2321
|
console.log(
|
|
1942
|
-
|
|
2322
|
+
chalk14.green("\u2713"),
|
|
1943
2323
|
`Task completed in ${finalStepCount} steps.`
|
|
1944
2324
|
);
|
|
1945
2325
|
if (maxStepsReached) {
|
|
1946
2326
|
console.log(
|
|
1947
|
-
|
|
2327
|
+
chalk14.yellow("\u26A0"),
|
|
1948
2328
|
"Maximum steps reached. Task may be incomplete."
|
|
1949
2329
|
);
|
|
1950
2330
|
}
|
|
@@ -1957,10 +2337,12 @@ var taskCommand = new Command23("task").description("Send a task to Claude runni
|
|
|
1957
2337
|
|
|
1958
2338
|
// src/cli.ts
|
|
1959
2339
|
var version = "0.1.0";
|
|
1960
|
-
var program = new
|
|
2340
|
+
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");
|
|
1961
2341
|
program.addCommand(loginCommand);
|
|
1962
2342
|
program.addCommand(logoutCommand);
|
|
1963
2343
|
program.addCommand(initCommand);
|
|
2344
|
+
program.addCommand(pushCommand);
|
|
2345
|
+
program.addCommand(devCommand);
|
|
1964
2346
|
program.addCommand(mcpCommand);
|
|
1965
2347
|
program.addCommand(taskCommand);
|
|
1966
2348
|
program.addCommand(orgCommand);
|