@waniwani/cli 0.0.26 → 0.0.28
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 +803 -433
- package/dist/index.js.map +1 -1
- package/package.json +5 -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,612 @@ 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 { readdir, readFile as readFile3, stat } 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 collectSingleFile(projectRoot, filePath) {
|
|
478
|
+
const fullPath = join3(projectRoot, filePath);
|
|
479
|
+
const relativePath = relative(projectRoot, fullPath);
|
|
480
|
+
if (!existsSync2(fullPath)) {
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
try {
|
|
484
|
+
const fileStat = await stat(fullPath);
|
|
485
|
+
if (!fileStat.isFile()) {
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
const content = await readFile3(fullPath);
|
|
489
|
+
const isBinary = isBinaryPath(fullPath) || detectBinary(content);
|
|
490
|
+
return {
|
|
491
|
+
path: relativePath,
|
|
492
|
+
content: isBinary ? content.toString("base64") : content.toString("utf8"),
|
|
493
|
+
encoding: isBinary ? "base64" : "utf8"
|
|
494
|
+
};
|
|
495
|
+
} catch {
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// src/commands/dev.ts
|
|
501
|
+
var BATCH_SIZE = 50;
|
|
502
|
+
var DEFAULT_DEBOUNCE_MS = 300;
|
|
503
|
+
var devCommand = new Command("dev").description("Watch and sync files to MCP sandbox").option("--no-initial-sync", "Skip initial sync of all files").option(
|
|
504
|
+
"--debounce <ms>",
|
|
505
|
+
"Debounce delay in milliseconds",
|
|
506
|
+
String(DEFAULT_DEBOUNCE_MS)
|
|
507
|
+
).action(async (options, command) => {
|
|
508
|
+
const globalOptions = command.optsWithGlobals();
|
|
509
|
+
const json = globalOptions.json ?? false;
|
|
510
|
+
try {
|
|
511
|
+
const cwd = process.cwd();
|
|
512
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
513
|
+
if (!projectRoot) {
|
|
514
|
+
throw new CLIError(
|
|
515
|
+
"Not in a WaniWani project. Run 'waniwani init <name>' first.",
|
|
516
|
+
"NOT_IN_PROJECT"
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
const mcpId = await loadProjectMcpId(projectRoot);
|
|
520
|
+
if (!mcpId) {
|
|
521
|
+
throw new CLIError(
|
|
522
|
+
"No MCP ID found in project config. Run 'waniwani init <name>' first.",
|
|
523
|
+
"NO_MCP_ID"
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
if (options.initialSync !== false) {
|
|
527
|
+
const spinner = ora("Initial sync...").start();
|
|
528
|
+
const files = await collectFiles(projectRoot);
|
|
529
|
+
if (files.length > 0) {
|
|
530
|
+
const totalBatches = Math.ceil(files.length / BATCH_SIZE);
|
|
531
|
+
let synced = 0;
|
|
532
|
+
for (let i = 0; i < totalBatches; i++) {
|
|
533
|
+
const batch = files.slice(i * BATCH_SIZE, (i + 1) * BATCH_SIZE);
|
|
534
|
+
spinner.text = `Syncing (${i + 1}/${totalBatches})...`;
|
|
535
|
+
const result = await api.post(
|
|
536
|
+
`/api/mcp/sandboxes/${mcpId}/files`,
|
|
537
|
+
{
|
|
538
|
+
files: batch.map((f) => ({
|
|
539
|
+
path: f.path,
|
|
540
|
+
content: f.content,
|
|
541
|
+
encoding: f.encoding
|
|
542
|
+
}))
|
|
543
|
+
}
|
|
544
|
+
);
|
|
545
|
+
synced += result.written.length;
|
|
546
|
+
}
|
|
547
|
+
spinner.succeed(`Initial sync complete (${synced} files)`);
|
|
548
|
+
} else {
|
|
549
|
+
spinner.info("No files to sync");
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
const ig = await loadIgnorePatterns(projectRoot);
|
|
553
|
+
const debounceMs = Number.parseInt(options.debounce, 10) || DEFAULT_DEBOUNCE_MS;
|
|
554
|
+
const syncFile = debounce(async (filePath) => {
|
|
555
|
+
const relativePath = relative2(projectRoot, filePath);
|
|
556
|
+
if (ig.ignores(relativePath)) {
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
const file = await collectSingleFile(projectRoot, relativePath);
|
|
560
|
+
if (!file) {
|
|
561
|
+
console.log(chalk2.yellow("Skipped:"), relativePath);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
try {
|
|
565
|
+
await api.post(
|
|
566
|
+
`/api/mcp/sandboxes/${mcpId}/files`,
|
|
567
|
+
{
|
|
568
|
+
files: [
|
|
569
|
+
{
|
|
570
|
+
path: file.path,
|
|
571
|
+
content: file.content,
|
|
572
|
+
encoding: file.encoding
|
|
573
|
+
}
|
|
574
|
+
]
|
|
575
|
+
}
|
|
576
|
+
);
|
|
577
|
+
console.log(chalk2.green("Synced:"), relativePath);
|
|
578
|
+
} catch (error) {
|
|
579
|
+
console.log(chalk2.red("Failed:"), relativePath);
|
|
580
|
+
if (globalOptions.verbose) {
|
|
581
|
+
console.error(error);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}, debounceMs);
|
|
585
|
+
console.log();
|
|
586
|
+
console.log(chalk2.bold("Watching for changes..."));
|
|
587
|
+
console.log(chalk2.dim("Press Ctrl+C to stop"));
|
|
588
|
+
console.log();
|
|
589
|
+
const watcher = chokidar.watch(projectRoot, {
|
|
590
|
+
ignored: (path) => {
|
|
591
|
+
const relativePath = relative2(projectRoot, path);
|
|
592
|
+
return ig.ignores(relativePath);
|
|
593
|
+
},
|
|
594
|
+
persistent: true,
|
|
595
|
+
ignoreInitial: true,
|
|
596
|
+
awaitWriteFinish: {
|
|
597
|
+
stabilityThreshold: 100,
|
|
598
|
+
pollInterval: 100
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
watcher.on("add", (path) => syncFile(path)).on("change", (path) => syncFile(path)).on("unlink", (path) => {
|
|
602
|
+
const relativePath = relative2(projectRoot, path);
|
|
603
|
+
console.log(chalk2.yellow("Deleted (local only):"), relativePath);
|
|
604
|
+
});
|
|
605
|
+
const cleanup = () => {
|
|
606
|
+
console.log();
|
|
607
|
+
console.log(chalk2.dim("Stopping watcher..."));
|
|
608
|
+
watcher.close().then(() => {
|
|
609
|
+
process.exit(0);
|
|
610
|
+
});
|
|
611
|
+
};
|
|
612
|
+
process.on("SIGINT", cleanup);
|
|
613
|
+
process.on("SIGTERM", cleanup);
|
|
614
|
+
} catch (error) {
|
|
615
|
+
handleError(error, json);
|
|
616
|
+
process.exit(1);
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
// src/commands/init.ts
|
|
621
|
+
import { existsSync as existsSync3 } from "fs";
|
|
622
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
623
|
+
import { join as join4 } from "path";
|
|
624
|
+
import { Command as Command2 } from "commander";
|
|
625
|
+
import degit from "degit";
|
|
626
|
+
import ora2 from "ora";
|
|
627
|
+
|
|
628
|
+
// src/lib/output.ts
|
|
629
|
+
import chalk3 from "chalk";
|
|
630
|
+
function formatOutput(data, json) {
|
|
631
|
+
if (json) {
|
|
632
|
+
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
633
|
+
} else {
|
|
634
|
+
prettyPrint(data);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
function formatSuccess(message, json) {
|
|
638
|
+
if (json) {
|
|
639
|
+
console.log(JSON.stringify({ success: true, message }));
|
|
640
|
+
} else {
|
|
641
|
+
console.log(chalk3.green("\u2713"), message);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
function formatTable(headers, rows, json) {
|
|
645
|
+
if (json) {
|
|
646
|
+
const data = rows.map(
|
|
647
|
+
(row) => Object.fromEntries(headers.map((header, i) => [header, row[i]]))
|
|
648
|
+
);
|
|
649
|
+
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
650
|
+
} else {
|
|
651
|
+
const colWidths = headers.map(
|
|
652
|
+
(h, i) => Math.max(h.length, ...rows.map((r) => (r[i] || "").length))
|
|
653
|
+
);
|
|
654
|
+
const separator = colWidths.map((w) => "-".repeat(w + 2)).join("+");
|
|
655
|
+
const formatRow = (row) => row.map((cell, i) => ` ${(cell || "").padEnd(colWidths[i])} `).join("|");
|
|
656
|
+
console.log(chalk3.cyan(formatRow(headers)));
|
|
657
|
+
console.log(separator);
|
|
658
|
+
for (const row of rows) {
|
|
659
|
+
console.log(formatRow(row));
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
function formatList(items, json) {
|
|
664
|
+
if (json) {
|
|
665
|
+
const data = Object.fromEntries(
|
|
666
|
+
items.map((item) => [item.label, item.value])
|
|
667
|
+
);
|
|
668
|
+
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
669
|
+
} else {
|
|
670
|
+
const maxLabelLength = Math.max(...items.map((i) => i.label.length));
|
|
671
|
+
items.forEach((item) => {
|
|
672
|
+
console.log(
|
|
673
|
+
`${chalk3.gray(item.label.padEnd(maxLabelLength))} ${chalk3.white(item.value)}`
|
|
674
|
+
);
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
function prettyPrint(data, indent = 0) {
|
|
679
|
+
const prefix = " ".repeat(indent);
|
|
680
|
+
if (Array.isArray(data)) {
|
|
681
|
+
data.forEach((item, index) => {
|
|
682
|
+
console.log(`${prefix}${chalk3.gray(`[${index}]`)}`);
|
|
683
|
+
prettyPrint(item, indent + 1);
|
|
684
|
+
});
|
|
685
|
+
} else if (typeof data === "object" && data !== null) {
|
|
686
|
+
for (const [key, value] of Object.entries(data)) {
|
|
687
|
+
if (typeof value === "object" && value !== null) {
|
|
688
|
+
console.log(`${prefix}${chalk3.gray(key)}:`);
|
|
689
|
+
prettyPrint(value, indent + 1);
|
|
690
|
+
} else {
|
|
691
|
+
console.log(
|
|
692
|
+
`${prefix}${chalk3.gray(key)}: ${chalk3.white(String(value))}`
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
} else {
|
|
697
|
+
console.log(`${prefix}${chalk3.white(String(data))}`);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// src/commands/init.ts
|
|
702
|
+
var PROJECT_CONFIG_DIR = ".waniwani";
|
|
703
|
+
var PROJECT_CONFIG_FILE = "settings.json";
|
|
704
|
+
var initCommand = new Command2("init").description("Create a new MCP project from template").argument("<name>", "Name for the MCP project").action(async (name, _, command) => {
|
|
705
|
+
const globalOptions = command.optsWithGlobals();
|
|
706
|
+
const json = globalOptions.json ?? false;
|
|
707
|
+
try {
|
|
708
|
+
const cwd = process.cwd();
|
|
709
|
+
const projectDir = join4(cwd, name);
|
|
710
|
+
if (existsSync3(projectDir)) {
|
|
711
|
+
if (json) {
|
|
712
|
+
formatOutput(
|
|
713
|
+
{
|
|
714
|
+
success: false,
|
|
715
|
+
error: `Directory "${name}" already exists`
|
|
716
|
+
},
|
|
717
|
+
true
|
|
718
|
+
);
|
|
719
|
+
} else {
|
|
720
|
+
console.error(`Error: Directory "${name}" already exists`);
|
|
721
|
+
}
|
|
722
|
+
process.exit(1);
|
|
723
|
+
}
|
|
724
|
+
const spinner = ora2("Creating MCP sandbox...").start();
|
|
725
|
+
const result = await api.post("/api/mcp/sandboxes", {
|
|
726
|
+
name
|
|
727
|
+
});
|
|
728
|
+
spinner.text = "Cloning template...";
|
|
729
|
+
const templateRef = result.templateBranch ? `${result.templateGitUrl}#${result.templateBranch}` : result.templateGitUrl;
|
|
730
|
+
const emitter = degit(templateRef, {
|
|
731
|
+
cache: false,
|
|
732
|
+
force: true,
|
|
733
|
+
verbose: false
|
|
734
|
+
});
|
|
735
|
+
await emitter.clone(projectDir);
|
|
736
|
+
spinner.text = "Setting up project config...";
|
|
737
|
+
const configDir = join4(projectDir, PROJECT_CONFIG_DIR);
|
|
738
|
+
const configPath = join4(configDir, PROJECT_CONFIG_FILE);
|
|
739
|
+
await mkdir3(configDir, { recursive: true });
|
|
740
|
+
const projectConfig = {
|
|
741
|
+
mcpId: result.id,
|
|
742
|
+
defaults: {
|
|
743
|
+
model: "claude-sonnet-4-20250514",
|
|
744
|
+
maxSteps: 10
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
await writeFile3(
|
|
748
|
+
configPath,
|
|
749
|
+
JSON.stringify(projectConfig, null, " "),
|
|
750
|
+
"utf-8"
|
|
751
|
+
);
|
|
752
|
+
spinner.succeed("MCP project created");
|
|
753
|
+
if (json) {
|
|
754
|
+
formatOutput(
|
|
755
|
+
{
|
|
756
|
+
success: true,
|
|
757
|
+
projectDir,
|
|
758
|
+
mcpId: result.id,
|
|
759
|
+
sandboxId: result.sandboxId,
|
|
760
|
+
previewUrl: result.previewUrl
|
|
761
|
+
},
|
|
762
|
+
true
|
|
367
763
|
);
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
764
|
+
} else {
|
|
765
|
+
console.log();
|
|
766
|
+
formatSuccess(`MCP project "${name}" created!`, false);
|
|
767
|
+
console.log();
|
|
768
|
+
console.log(` Project: ${projectDir}`);
|
|
769
|
+
console.log(` MCP ID: ${result.id}`);
|
|
770
|
+
console.log(` Preview URL: ${result.previewUrl}`);
|
|
771
|
+
console.log();
|
|
772
|
+
console.log("Next steps:");
|
|
773
|
+
console.log(` cd ${name}`);
|
|
774
|
+
console.log(" waniwani push # Sync files to sandbox");
|
|
775
|
+
console.log(" waniwani dev # Watch mode with auto-sync");
|
|
776
|
+
console.log(' waniwani task "..." # Send tasks to Claude');
|
|
372
777
|
}
|
|
778
|
+
} catch (error) {
|
|
779
|
+
handleError(error, json);
|
|
780
|
+
process.exit(1);
|
|
373
781
|
}
|
|
374
|
-
};
|
|
375
|
-
var auth = new AuthManager();
|
|
782
|
+
});
|
|
376
783
|
|
|
377
784
|
// src/commands/login.ts
|
|
785
|
+
import { spawn } from "child_process";
|
|
786
|
+
import { createServer } from "http";
|
|
787
|
+
import chalk4 from "chalk";
|
|
788
|
+
import { Command as Command3 } from "commander";
|
|
789
|
+
import ora3 from "ora";
|
|
378
790
|
var CALLBACK_PORT = 54321;
|
|
379
791
|
var CALLBACK_URL = `http://localhost:${CALLBACK_PORT}/callback`;
|
|
380
792
|
var CLIENT_NAME = "waniwani-cli";
|
|
@@ -649,7 +1061,7 @@ async function exchangeCodeForToken(code, codeVerifier, clientId, resource) {
|
|
|
649
1061
|
}
|
|
650
1062
|
return response.json();
|
|
651
1063
|
}
|
|
652
|
-
var loginCommand = new
|
|
1064
|
+
var loginCommand = new Command3("login").description("Log in to WaniWani").option("--no-browser", "Don't open the browser automatically").action(async (options, command) => {
|
|
653
1065
|
const globalOptions = command.optsWithGlobals();
|
|
654
1066
|
const json = globalOptions.json ?? false;
|
|
655
1067
|
try {
|
|
@@ -661,14 +1073,14 @@ var loginCommand = new Command2("login").description("Log in to WaniWani").optio
|
|
|
661
1073
|
formatOutput({ alreadyLoggedIn: true, refreshed: true }, true);
|
|
662
1074
|
} else {
|
|
663
1075
|
console.log(
|
|
664
|
-
|
|
1076
|
+
chalk4.green("Session refreshed. You're still logged in.")
|
|
665
1077
|
);
|
|
666
1078
|
}
|
|
667
1079
|
return;
|
|
668
1080
|
}
|
|
669
1081
|
if (!json) {
|
|
670
1082
|
console.log(
|
|
671
|
-
|
|
1083
|
+
chalk4.yellow("Session expired. Starting new login flow...")
|
|
672
1084
|
);
|
|
673
1085
|
}
|
|
674
1086
|
await auth.clear();
|
|
@@ -677,7 +1089,7 @@ var loginCommand = new Command2("login").description("Log in to WaniWani").optio
|
|
|
677
1089
|
formatOutput({ alreadyLoggedIn: true }, true);
|
|
678
1090
|
} else {
|
|
679
1091
|
console.log(
|
|
680
|
-
|
|
1092
|
+
chalk4.yellow(
|
|
681
1093
|
"Already logged in. Use 'waniwani logout' to log out first."
|
|
682
1094
|
)
|
|
683
1095
|
);
|
|
@@ -686,9 +1098,9 @@ var loginCommand = new Command2("login").description("Log in to WaniWani").optio
|
|
|
686
1098
|
}
|
|
687
1099
|
}
|
|
688
1100
|
if (!json) {
|
|
689
|
-
console.log(
|
|
1101
|
+
console.log(chalk4.bold("\nWaniWani CLI Login\n"));
|
|
690
1102
|
}
|
|
691
|
-
const spinner =
|
|
1103
|
+
const spinner = ora3("Registering client...").start();
|
|
692
1104
|
const { client_id: clientId } = await registerClient();
|
|
693
1105
|
spinner.text = "Preparing authentication...";
|
|
694
1106
|
const codeVerifier = generateCodeVerifier();
|
|
@@ -708,7 +1120,7 @@ var loginCommand = new Command2("login").description("Log in to WaniWani").optio
|
|
|
708
1120
|
console.log("Opening browser for authentication...\n");
|
|
709
1121
|
console.log(`If the browser doesn't open, visit:
|
|
710
1122
|
`);
|
|
711
|
-
console.log(
|
|
1123
|
+
console.log(chalk4.cyan(` ${authUrl.toString()}`));
|
|
712
1124
|
console.log();
|
|
713
1125
|
}
|
|
714
1126
|
const callbackPromise = waitForCallback(state);
|
|
@@ -754,8 +1166,8 @@ var loginCommand = new Command2("login").description("Log in to WaniWani").optio
|
|
|
754
1166
|
});
|
|
755
1167
|
|
|
756
1168
|
// src/commands/logout.ts
|
|
757
|
-
import { Command as
|
|
758
|
-
var logoutCommand = new
|
|
1169
|
+
import { Command as Command4 } from "commander";
|
|
1170
|
+
var logoutCommand = new Command4("logout").description("Log out from WaniWani").action(async (_, command) => {
|
|
759
1171
|
const globalOptions = command.optsWithGlobals();
|
|
760
1172
|
const json = globalOptions.json ?? false;
|
|
761
1173
|
try {
|
|
@@ -782,134 +1194,9 @@ var logoutCommand = new Command3("logout").description("Log out from WaniWani").
|
|
|
782
1194
|
// src/commands/mcp/index.ts
|
|
783
1195
|
import { Command as Command19 } from "commander";
|
|
784
1196
|
|
|
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
1197
|
// src/commands/mcp/delete.ts
|
|
911
1198
|
import { Command as Command5 } from "commander";
|
|
912
|
-
import
|
|
1199
|
+
import ora4 from "ora";
|
|
913
1200
|
var deleteCommand = new Command5("delete").description("Delete the MCP sandbox").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
914
1201
|
const globalOptions = command.optsWithGlobals();
|
|
915
1202
|
const json = globalOptions.json ?? false;
|
|
@@ -921,7 +1208,7 @@ var deleteCommand = new Command5("delete").description("Delete the MCP sandbox")
|
|
|
921
1208
|
throw new McpError("No active MCP. Use --mcp-id to specify one.");
|
|
922
1209
|
}
|
|
923
1210
|
}
|
|
924
|
-
const spinner =
|
|
1211
|
+
const spinner = ora4("Deleting MCP sandbox...").start();
|
|
925
1212
|
await api.delete(`/api/mcp/sandboxes/${mcpId}`);
|
|
926
1213
|
spinner.succeed("MCP sandbox deleted");
|
|
927
1214
|
if (await config.getMcpId() === mcpId) {
|
|
@@ -940,7 +1227,7 @@ var deleteCommand = new Command5("delete").description("Delete the MCP sandbox")
|
|
|
940
1227
|
|
|
941
1228
|
// src/commands/mcp/deploy.ts
|
|
942
1229
|
import { Command as Command6 } from "commander";
|
|
943
|
-
import
|
|
1230
|
+
import ora5 from "ora";
|
|
944
1231
|
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
1232
|
const globalOptions = command.optsWithGlobals();
|
|
946
1233
|
const json = globalOptions.json ?? false;
|
|
@@ -954,7 +1241,7 @@ var deployCommand = new Command6("deploy").description("Deploy MCP server to Git
|
|
|
954
1241
|
);
|
|
955
1242
|
}
|
|
956
1243
|
}
|
|
957
|
-
const spinner =
|
|
1244
|
+
const spinner = ora5("Deploying to GitHub...").start();
|
|
958
1245
|
const result = await api.post(
|
|
959
1246
|
`/api/admin/mcps/${mcpId}/deploy`,
|
|
960
1247
|
{
|
|
@@ -989,9 +1276,9 @@ var deployCommand = new Command6("deploy").description("Deploy MCP server to Git
|
|
|
989
1276
|
import { Command as Command10 } from "commander";
|
|
990
1277
|
|
|
991
1278
|
// src/commands/mcp/file/list.ts
|
|
992
|
-
import
|
|
1279
|
+
import chalk5 from "chalk";
|
|
993
1280
|
import { Command as Command7 } from "commander";
|
|
994
|
-
import
|
|
1281
|
+
import ora6 from "ora";
|
|
995
1282
|
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
1283
|
const globalOptions = command.optsWithGlobals();
|
|
997
1284
|
const json = globalOptions.json ?? false;
|
|
@@ -1005,7 +1292,7 @@ var listCommand = new Command7("list").description("List files in the MCP sandbo
|
|
|
1005
1292
|
);
|
|
1006
1293
|
}
|
|
1007
1294
|
}
|
|
1008
|
-
const spinner =
|
|
1295
|
+
const spinner = ora6(`Listing ${path}...`).start();
|
|
1009
1296
|
const result = await api.get(
|
|
1010
1297
|
`/api/mcp/sandboxes/${mcpId}/files/list?path=${encodeURIComponent(path)}`
|
|
1011
1298
|
);
|
|
@@ -1013,15 +1300,15 @@ var listCommand = new Command7("list").description("List files in the MCP sandbo
|
|
|
1013
1300
|
if (json) {
|
|
1014
1301
|
formatOutput(result, true);
|
|
1015
1302
|
} else {
|
|
1016
|
-
console.log(
|
|
1303
|
+
console.log(chalk5.bold(`
|
|
1017
1304
|
Directory: ${result.path}
|
|
1018
1305
|
`));
|
|
1019
1306
|
if (result.entries.length === 0) {
|
|
1020
1307
|
console.log(" (empty)");
|
|
1021
1308
|
} else {
|
|
1022
1309
|
const rows = result.entries.map((entry) => {
|
|
1023
|
-
const name = entry.type === "directory" ?
|
|
1024
|
-
const size = entry.type === "directory" ?
|
|
1310
|
+
const name = entry.type === "directory" ? chalk5.blue(`${entry.name}/`) : entry.name;
|
|
1311
|
+
const size = entry.type === "directory" ? chalk5.gray("<dir>") : formatSize(entry.size);
|
|
1025
1312
|
return [name, size];
|
|
1026
1313
|
});
|
|
1027
1314
|
formatTable(["Name", "Size"], rows, false);
|
|
@@ -1043,7 +1330,7 @@ function formatSize(bytes) {
|
|
|
1043
1330
|
// src/commands/mcp/file/read.ts
|
|
1044
1331
|
import { writeFile as writeFile4 } from "fs/promises";
|
|
1045
1332
|
import { Command as Command8 } from "commander";
|
|
1046
|
-
import
|
|
1333
|
+
import ora7 from "ora";
|
|
1047
1334
|
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
1335
|
const globalOptions = command.optsWithGlobals();
|
|
1049
1336
|
const json = globalOptions.json ?? false;
|
|
@@ -1058,7 +1345,7 @@ var readCommand = new Command8("read").description("Read a file from the MCP san
|
|
|
1058
1345
|
}
|
|
1059
1346
|
}
|
|
1060
1347
|
const encoding = options.base64 ? "base64" : "utf8";
|
|
1061
|
-
const spinner =
|
|
1348
|
+
const spinner = ora7(`Reading ${path}...`).start();
|
|
1062
1349
|
const result = await api.get(
|
|
1063
1350
|
`/api/mcp/sandboxes/${mcpId}/files?path=${encodeURIComponent(path)}&encoding=${encoding}`
|
|
1064
1351
|
);
|
|
@@ -1089,9 +1376,9 @@ var readCommand = new Command8("read").description("Read a file from the MCP san
|
|
|
1089
1376
|
});
|
|
1090
1377
|
|
|
1091
1378
|
// src/commands/mcp/file/write.ts
|
|
1092
|
-
import { readFile as
|
|
1379
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
1093
1380
|
import { Command as Command9 } from "commander";
|
|
1094
|
-
import
|
|
1381
|
+
import ora8 from "ora";
|
|
1095
1382
|
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
1383
|
const globalOptions = command.optsWithGlobals();
|
|
1097
1384
|
const json = globalOptions.json ?? false;
|
|
@@ -1113,7 +1400,7 @@ var writeCommand = new Command9("write").description("Write a file to the MCP sa
|
|
|
1113
1400
|
encoding = "base64";
|
|
1114
1401
|
}
|
|
1115
1402
|
} else if (options.file) {
|
|
1116
|
-
const fileBuffer = await
|
|
1403
|
+
const fileBuffer = await readFile4(options.file);
|
|
1117
1404
|
if (options.base64) {
|
|
1118
1405
|
content = fileBuffer.toString("base64");
|
|
1119
1406
|
encoding = "base64";
|
|
@@ -1126,7 +1413,7 @@ var writeCommand = new Command9("write").description("Write a file to the MCP sa
|
|
|
1126
1413
|
"MISSING_CONTENT"
|
|
1127
1414
|
);
|
|
1128
1415
|
}
|
|
1129
|
-
const spinner =
|
|
1416
|
+
const spinner = ora8(`Writing ${path}...`).start();
|
|
1130
1417
|
const result = await api.post(
|
|
1131
1418
|
`/api/mcp/sandboxes/${mcpId}/files`,
|
|
1132
1419
|
{
|
|
@@ -1149,14 +1436,14 @@ var writeCommand = new Command9("write").description("Write a file to the MCP sa
|
|
|
1149
1436
|
var fileCommand = new Command10("file").description("File operations in MCP sandbox").addCommand(readCommand).addCommand(writeCommand).addCommand(listCommand);
|
|
1150
1437
|
|
|
1151
1438
|
// src/commands/mcp/list.ts
|
|
1152
|
-
import
|
|
1439
|
+
import chalk6 from "chalk";
|
|
1153
1440
|
import { Command as Command11 } from "commander";
|
|
1154
|
-
import
|
|
1441
|
+
import ora9 from "ora";
|
|
1155
1442
|
var listCommand2 = new Command11("list").description("List all MCPs in your organization").option("--all", "Include stopped/expired MCPs").action(async (options, command) => {
|
|
1156
1443
|
const globalOptions = command.optsWithGlobals();
|
|
1157
1444
|
const json = globalOptions.json ?? false;
|
|
1158
1445
|
try {
|
|
1159
|
-
const spinner =
|
|
1446
|
+
const spinner = ora9("Fetching MCPs...").start();
|
|
1160
1447
|
const mcps = await api.get(
|
|
1161
1448
|
`/api/mcp/sandboxes${options.all ? "?all=true" : ""}`
|
|
1162
1449
|
);
|
|
@@ -1179,12 +1466,12 @@ var listCommand2 = new Command11("list").description("List all MCPs in your orga
|
|
|
1179
1466
|
console.log("\nCreate a new MCP sandbox: waniwani mcp create <name>");
|
|
1180
1467
|
return;
|
|
1181
1468
|
}
|
|
1182
|
-
console.log(
|
|
1469
|
+
console.log(chalk6.bold("\nMCPs:\n"));
|
|
1183
1470
|
const rows = mcps.map((m) => {
|
|
1184
1471
|
const isActive = m.id === activeMcpId;
|
|
1185
|
-
const statusColor = m.status === "active" ?
|
|
1472
|
+
const statusColor = m.status === "active" ? chalk6.green : m.status === "stopped" ? chalk6.red : chalk6.yellow;
|
|
1186
1473
|
return [
|
|
1187
|
-
isActive ?
|
|
1474
|
+
isActive ? chalk6.cyan(`* ${m.id.slice(0, 8)}`) : ` ${m.id.slice(0, 8)}`,
|
|
1188
1475
|
m.name,
|
|
1189
1476
|
statusColor(m.status),
|
|
1190
1477
|
m.previewUrl,
|
|
@@ -1198,7 +1485,7 @@ var listCommand2 = new Command11("list").description("List all MCPs in your orga
|
|
|
1198
1485
|
);
|
|
1199
1486
|
console.log();
|
|
1200
1487
|
if (activeMcpId) {
|
|
1201
|
-
console.log(`Active MCP: ${
|
|
1488
|
+
console.log(`Active MCP: ${chalk6.cyan(activeMcpId.slice(0, 8))}`);
|
|
1202
1489
|
}
|
|
1203
1490
|
console.log("\nSelect an MCP: waniwani mcp use <name>");
|
|
1204
1491
|
}
|
|
@@ -1209,9 +1496,9 @@ var listCommand2 = new Command11("list").description("List all MCPs in your orga
|
|
|
1209
1496
|
});
|
|
1210
1497
|
|
|
1211
1498
|
// src/commands/mcp/logs.ts
|
|
1212
|
-
import
|
|
1499
|
+
import chalk7 from "chalk";
|
|
1213
1500
|
import { Command as Command12 } from "commander";
|
|
1214
|
-
import
|
|
1501
|
+
import ora10 from "ora";
|
|
1215
1502
|
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
1503
|
const globalOptions = command.optsWithGlobals();
|
|
1217
1504
|
const json = globalOptions.json ?? false;
|
|
@@ -1243,7 +1530,7 @@ var logsCommand = new Command12("logs").description("Stream logs from the MCP se
|
|
|
1243
1530
|
}
|
|
1244
1531
|
let cmdId = cmdIdArg;
|
|
1245
1532
|
if (!cmdId) {
|
|
1246
|
-
const spinner =
|
|
1533
|
+
const spinner = ora10("Getting server status...").start();
|
|
1247
1534
|
const status = await api.post(
|
|
1248
1535
|
`/api/mcp/sandboxes/${mcpId}/server`,
|
|
1249
1536
|
{ action: "status" }
|
|
@@ -1260,8 +1547,8 @@ var logsCommand = new Command12("logs").description("Stream logs from the MCP se
|
|
|
1260
1547
|
const streamParam = options.follow ? "?stream=true" : "";
|
|
1261
1548
|
const url = `${baseUrl}/api/mcp/sandboxes/${mcpId}/commands/${cmdId}${streamParam}`;
|
|
1262
1549
|
if (!json) {
|
|
1263
|
-
console.log(
|
|
1264
|
-
console.log(
|
|
1550
|
+
console.log(chalk7.gray(`Streaming logs for command ${cmdId}...`));
|
|
1551
|
+
console.log(chalk7.gray("Press Ctrl+C to stop\n"));
|
|
1265
1552
|
}
|
|
1266
1553
|
const response = await fetch(url, {
|
|
1267
1554
|
method: "GET",
|
|
@@ -1285,10 +1572,10 @@ var logsCommand = new Command12("logs").description("Stream logs from the MCP se
|
|
|
1285
1572
|
process.stdout.write(data.stdout);
|
|
1286
1573
|
}
|
|
1287
1574
|
if (data.stderr) {
|
|
1288
|
-
process.stderr.write(
|
|
1575
|
+
process.stderr.write(chalk7.red(data.stderr));
|
|
1289
1576
|
}
|
|
1290
1577
|
if (data.exitCode !== void 0) {
|
|
1291
|
-
console.log(
|
|
1578
|
+
console.log(chalk7.gray(`
|
|
1292
1579
|
Exit code: ${data.exitCode}`));
|
|
1293
1580
|
}
|
|
1294
1581
|
}
|
|
@@ -1327,18 +1614,18 @@ Exit code: ${data.exitCode}`));
|
|
|
1327
1614
|
if (event.stream === "stdout") {
|
|
1328
1615
|
process.stdout.write(event.data);
|
|
1329
1616
|
} else if (event.stream === "stderr") {
|
|
1330
|
-
process.stderr.write(
|
|
1617
|
+
process.stderr.write(chalk7.red(event.data));
|
|
1331
1618
|
}
|
|
1332
1619
|
}
|
|
1333
1620
|
if (event.exitCode !== void 0) {
|
|
1334
|
-
const exitColor = event.exitCode === 0 ?
|
|
1621
|
+
const exitColor = event.exitCode === 0 ? chalk7.green : chalk7.red;
|
|
1335
1622
|
console.log(
|
|
1336
1623
|
exitColor(`
|
|
1337
1624
|
Process exited with code ${event.exitCode}`)
|
|
1338
1625
|
);
|
|
1339
1626
|
}
|
|
1340
1627
|
if (event.error) {
|
|
1341
|
-
console.error(
|
|
1628
|
+
console.error(chalk7.red(`
|
|
1342
1629
|
Error: ${event.error}`));
|
|
1343
1630
|
}
|
|
1344
1631
|
} catch {
|
|
@@ -1359,9 +1646,9 @@ Error: ${event.error}`));
|
|
|
1359
1646
|
});
|
|
1360
1647
|
|
|
1361
1648
|
// src/commands/mcp/run-command.ts
|
|
1362
|
-
import
|
|
1649
|
+
import chalk8 from "chalk";
|
|
1363
1650
|
import { Command as Command13 } from "commander";
|
|
1364
|
-
import
|
|
1651
|
+
import ora11 from "ora";
|
|
1365
1652
|
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
1653
|
"--timeout <ms>",
|
|
1367
1654
|
"Command timeout in milliseconds (default: 30000, max: 300000)"
|
|
@@ -1379,7 +1666,7 @@ var runCommandCommand = new Command13("run-command").description("Run a command
|
|
|
1379
1666
|
}
|
|
1380
1667
|
}
|
|
1381
1668
|
const timeout = options.timeout ? Number.parseInt(options.timeout, 10) : void 0;
|
|
1382
|
-
const spinner =
|
|
1669
|
+
const spinner = ora11(`Running: ${cmd} ${args.join(" ")}`.trim()).start();
|
|
1383
1670
|
const result = await api.post(
|
|
1384
1671
|
`/api/mcp/sandboxes/${mcpId}/commands`,
|
|
1385
1672
|
{
|
|
@@ -1394,7 +1681,7 @@ var runCommandCommand = new Command13("run-command").description("Run a command
|
|
|
1394
1681
|
formatOutput(result, true);
|
|
1395
1682
|
} else {
|
|
1396
1683
|
const cmdLine = [cmd, ...args].join(" ");
|
|
1397
|
-
console.log(
|
|
1684
|
+
console.log(chalk8.gray(`$ ${cmdLine}`));
|
|
1398
1685
|
console.log();
|
|
1399
1686
|
if (result.stdout) {
|
|
1400
1687
|
process.stdout.write(result.stdout);
|
|
@@ -1403,16 +1690,16 @@ var runCommandCommand = new Command13("run-command").description("Run a command
|
|
|
1403
1690
|
}
|
|
1404
1691
|
}
|
|
1405
1692
|
if (result.stderr) {
|
|
1406
|
-
process.stderr.write(
|
|
1693
|
+
process.stderr.write(chalk8.red(result.stderr));
|
|
1407
1694
|
if (!result.stderr.endsWith("\n")) {
|
|
1408
1695
|
process.stderr.write("\n");
|
|
1409
1696
|
}
|
|
1410
1697
|
}
|
|
1411
1698
|
console.log();
|
|
1412
|
-
const exitColor = result.exitCode === 0 ?
|
|
1699
|
+
const exitColor = result.exitCode === 0 ? chalk8.green : chalk8.red;
|
|
1413
1700
|
console.log(
|
|
1414
1701
|
exitColor(`Exit code: ${result.exitCode}`),
|
|
1415
|
-
|
|
1702
|
+
chalk8.gray(`(${(result.duration / 1e3).toFixed(2)}s)`)
|
|
1416
1703
|
);
|
|
1417
1704
|
}
|
|
1418
1705
|
if (result.exitCode !== 0) {
|
|
@@ -1425,9 +1712,9 @@ var runCommandCommand = new Command13("run-command").description("Run a command
|
|
|
1425
1712
|
});
|
|
1426
1713
|
|
|
1427
1714
|
// src/commands/mcp/start.ts
|
|
1428
|
-
import
|
|
1715
|
+
import chalk9 from "chalk";
|
|
1429
1716
|
import { Command as Command14 } from "commander";
|
|
1430
|
-
import
|
|
1717
|
+
import ora12 from "ora";
|
|
1431
1718
|
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
1719
|
const globalOptions = command.optsWithGlobals();
|
|
1433
1720
|
const json = globalOptions.json ?? false;
|
|
@@ -1441,7 +1728,7 @@ var startCommand = new Command14("start").description("Start the MCP server (npm
|
|
|
1441
1728
|
);
|
|
1442
1729
|
}
|
|
1443
1730
|
}
|
|
1444
|
-
const spinner =
|
|
1731
|
+
const spinner = ora12("Starting MCP server...").start();
|
|
1445
1732
|
const result = await api.post(
|
|
1446
1733
|
`/api/mcp/sandboxes/${mcpId}/server`,
|
|
1447
1734
|
{ action: "start" }
|
|
@@ -1454,13 +1741,13 @@ var startCommand = new Command14("start").description("Start the MCP server (npm
|
|
|
1454
1741
|
formatList(
|
|
1455
1742
|
[
|
|
1456
1743
|
{ label: "Command ID", value: result.cmdId },
|
|
1457
|
-
{ label: "Preview URL", value:
|
|
1744
|
+
{ label: "Preview URL", value: chalk9.cyan(result.previewUrl) }
|
|
1458
1745
|
],
|
|
1459
1746
|
false
|
|
1460
1747
|
);
|
|
1461
1748
|
console.log();
|
|
1462
1749
|
console.log(
|
|
1463
|
-
|
|
1750
|
+
chalk9.gray("Run 'waniwani mcp logs' to stream server output")
|
|
1464
1751
|
);
|
|
1465
1752
|
}
|
|
1466
1753
|
} catch (error) {
|
|
@@ -1470,9 +1757,9 @@ var startCommand = new Command14("start").description("Start the MCP server (npm
|
|
|
1470
1757
|
});
|
|
1471
1758
|
|
|
1472
1759
|
// src/commands/mcp/status.ts
|
|
1473
|
-
import
|
|
1760
|
+
import chalk10 from "chalk";
|
|
1474
1761
|
import { Command as Command15 } from "commander";
|
|
1475
|
-
import
|
|
1762
|
+
import ora13 from "ora";
|
|
1476
1763
|
var statusCommand = new Command15("status").description("Show current MCP sandbox status").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1477
1764
|
const globalOptions = command.optsWithGlobals();
|
|
1478
1765
|
const json = globalOptions.json ?? false;
|
|
@@ -1486,7 +1773,7 @@ var statusCommand = new Command15("status").description("Show current MCP sandbo
|
|
|
1486
1773
|
);
|
|
1487
1774
|
}
|
|
1488
1775
|
}
|
|
1489
|
-
const spinner =
|
|
1776
|
+
const spinner = ora13("Fetching MCP status...").start();
|
|
1490
1777
|
const [result, serverStatus] = await Promise.all([
|
|
1491
1778
|
api.get(`/api/mcp/sandboxes/${mcpId}`),
|
|
1492
1779
|
api.post(`/api/mcp/sandboxes/${mcpId}/server`, {
|
|
@@ -1501,9 +1788,9 @@ var statusCommand = new Command15("status").description("Show current MCP sandbo
|
|
|
1501
1788
|
if (json) {
|
|
1502
1789
|
formatOutput({ ...result, server: serverStatus }, true);
|
|
1503
1790
|
} else {
|
|
1504
|
-
const statusColor = result.status === "active" ?
|
|
1791
|
+
const statusColor = result.status === "active" ? chalk10.green : chalk10.red;
|
|
1505
1792
|
const serverRunning = serverStatus.running;
|
|
1506
|
-
const serverStatusColor = serverRunning ?
|
|
1793
|
+
const serverStatusColor = serverRunning ? chalk10.green : chalk10.yellow;
|
|
1507
1794
|
formatList(
|
|
1508
1795
|
[
|
|
1509
1796
|
{ label: "MCP ID", value: result.id },
|
|
@@ -1530,7 +1817,7 @@ var statusCommand = new Command15("status").description("Show current MCP sandbo
|
|
|
1530
1817
|
|
|
1531
1818
|
// src/commands/mcp/stop.ts
|
|
1532
1819
|
import { Command as Command16 } from "commander";
|
|
1533
|
-
import
|
|
1820
|
+
import ora14 from "ora";
|
|
1534
1821
|
var stopCommand = new Command16("stop").description("Stop the MCP server process").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1535
1822
|
const globalOptions = command.optsWithGlobals();
|
|
1536
1823
|
const json = globalOptions.json ?? false;
|
|
@@ -1544,7 +1831,7 @@ var stopCommand = new Command16("stop").description("Stop the MCP server process
|
|
|
1544
1831
|
);
|
|
1545
1832
|
}
|
|
1546
1833
|
}
|
|
1547
|
-
const spinner =
|
|
1834
|
+
const spinner = ora14("Stopping MCP server...").start();
|
|
1548
1835
|
const result = await api.post(
|
|
1549
1836
|
`/api/mcp/sandboxes/${mcpId}/server`,
|
|
1550
1837
|
{ action: "stop" }
|
|
@@ -1566,9 +1853,9 @@ var stopCommand = new Command16("stop").description("Stop the MCP server process
|
|
|
1566
1853
|
});
|
|
1567
1854
|
|
|
1568
1855
|
// src/commands/mcp/test.ts
|
|
1569
|
-
import
|
|
1856
|
+
import chalk11 from "chalk";
|
|
1570
1857
|
import { Command as Command17 } from "commander";
|
|
1571
|
-
import
|
|
1858
|
+
import ora15 from "ora";
|
|
1572
1859
|
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
1860
|
async (tool, args, options, command) => {
|
|
1574
1861
|
const globalOptions = command.optsWithGlobals();
|
|
@@ -1584,7 +1871,7 @@ var testCommand = new Command17("test").description("Test MCP tools via the sand
|
|
|
1584
1871
|
}
|
|
1585
1872
|
}
|
|
1586
1873
|
if (!tool) {
|
|
1587
|
-
const spinner =
|
|
1874
|
+
const spinner = ora15("Fetching available tools...").start();
|
|
1588
1875
|
const result = await api.post(
|
|
1589
1876
|
`/api/mcp/sandboxes/${mcpId}/test`,
|
|
1590
1877
|
{ action: "list" }
|
|
@@ -1597,7 +1884,7 @@ var testCommand = new Command17("test").description("Test MCP tools via the sand
|
|
|
1597
1884
|
if (tools.length === 0) {
|
|
1598
1885
|
console.log("No tools available.");
|
|
1599
1886
|
} else {
|
|
1600
|
-
console.log(
|
|
1887
|
+
console.log(chalk11.bold("\nAvailable Tools:\n"));
|
|
1601
1888
|
formatTable(
|
|
1602
1889
|
["Name", "Description"],
|
|
1603
1890
|
tools.map((t) => [t.name, t.description || "No description"]),
|
|
@@ -1620,7 +1907,7 @@ Test a tool: waniwani mcp test <tool-name> '{"arg": "value"}'`
|
|
|
1620
1907
|
);
|
|
1621
1908
|
}
|
|
1622
1909
|
}
|
|
1623
|
-
const spinner =
|
|
1910
|
+
const spinner = ora15(`Calling tool "${tool}"...`).start();
|
|
1624
1911
|
const startTime = Date.now();
|
|
1625
1912
|
const result = await api.post(
|
|
1626
1913
|
`/api/mcp/sandboxes/${mcpId}/test`,
|
|
@@ -1641,11 +1928,11 @@ Test a tool: waniwani mcp test <tool-name> '{"arg": "value"}'`
|
|
|
1641
1928
|
if (json) {
|
|
1642
1929
|
formatOutput(output, true);
|
|
1643
1930
|
} else {
|
|
1644
|
-
console.log(
|
|
1645
|
-
console.log(
|
|
1646
|
-
console.log(
|
|
1647
|
-
console.log(
|
|
1648
|
-
console.log(
|
|
1931
|
+
console.log(chalk11.bold("\nTool Result:\n"));
|
|
1932
|
+
console.log(chalk11.gray("Tool:"), tool);
|
|
1933
|
+
console.log(chalk11.gray("Input:"), JSON.stringify(toolArgs));
|
|
1934
|
+
console.log(chalk11.gray("Duration:"), `${duration}ms`);
|
|
1935
|
+
console.log(chalk11.gray("Result:"));
|
|
1649
1936
|
console.log(JSON.stringify(result.result, null, 2));
|
|
1650
1937
|
}
|
|
1651
1938
|
}
|
|
@@ -1658,12 +1945,12 @@ Test a tool: waniwani mcp test <tool-name> '{"arg": "value"}'`
|
|
|
1658
1945
|
|
|
1659
1946
|
// src/commands/mcp/use.ts
|
|
1660
1947
|
import { Command as Command18 } from "commander";
|
|
1661
|
-
import
|
|
1948
|
+
import ora16 from "ora";
|
|
1662
1949
|
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
1950
|
const globalOptions = command.optsWithGlobals();
|
|
1664
1951
|
const json = globalOptions.json ?? false;
|
|
1665
1952
|
try {
|
|
1666
|
-
const spinner =
|
|
1953
|
+
const spinner = ora16("Fetching MCPs...").start();
|
|
1667
1954
|
const mcps = await api.get("/api/admin/mcps");
|
|
1668
1955
|
spinner.stop();
|
|
1669
1956
|
const mcp = mcps.find((m) => m.name === name);
|
|
@@ -1699,20 +1986,20 @@ var useCommand = new Command18("use").description("Select an MCP to use for subs
|
|
|
1699
1986
|
});
|
|
1700
1987
|
|
|
1701
1988
|
// src/commands/mcp/index.ts
|
|
1702
|
-
var mcpCommand = new Command19("mcp").description("MCP sandbox management commands").addCommand(
|
|
1989
|
+
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
1990
|
|
|
1704
1991
|
// src/commands/org/index.ts
|
|
1705
1992
|
import { Command as Command22 } from "commander";
|
|
1706
1993
|
|
|
1707
1994
|
// src/commands/org/list.ts
|
|
1708
|
-
import
|
|
1995
|
+
import chalk12 from "chalk";
|
|
1709
1996
|
import { Command as Command20 } from "commander";
|
|
1710
|
-
import
|
|
1997
|
+
import ora17 from "ora";
|
|
1711
1998
|
var listCommand3 = new Command20("list").description("List your organizations").action(async (_, command) => {
|
|
1712
1999
|
const globalOptions = command.optsWithGlobals();
|
|
1713
2000
|
const json = globalOptions.json ?? false;
|
|
1714
2001
|
try {
|
|
1715
|
-
const spinner =
|
|
2002
|
+
const spinner = ora17("Fetching organizations...").start();
|
|
1716
2003
|
const result = await api.get("/api/oauth/orgs");
|
|
1717
2004
|
spinner.stop();
|
|
1718
2005
|
const { orgs, activeOrgId } = result;
|
|
@@ -1732,11 +2019,11 @@ var listCommand3 = new Command20("list").description("List your organizations").
|
|
|
1732
2019
|
console.log("No organizations found.");
|
|
1733
2020
|
return;
|
|
1734
2021
|
}
|
|
1735
|
-
console.log(
|
|
2022
|
+
console.log(chalk12.bold("\nOrganizations:\n"));
|
|
1736
2023
|
const rows = orgs.map((o) => {
|
|
1737
2024
|
const isActive = o.id === activeOrgId;
|
|
1738
2025
|
return [
|
|
1739
|
-
isActive ?
|
|
2026
|
+
isActive ? chalk12.cyan(`* ${o.name}`) : ` ${o.name}`,
|
|
1740
2027
|
o.slug,
|
|
1741
2028
|
o.role
|
|
1742
2029
|
];
|
|
@@ -1746,7 +2033,7 @@ var listCommand3 = new Command20("list").description("List your organizations").
|
|
|
1746
2033
|
if (activeOrgId) {
|
|
1747
2034
|
const activeOrg = orgs.find((o) => o.id === activeOrgId);
|
|
1748
2035
|
if (activeOrg) {
|
|
1749
|
-
console.log(`Active organization: ${
|
|
2036
|
+
console.log(`Active organization: ${chalk12.cyan(activeOrg.name)}`);
|
|
1750
2037
|
}
|
|
1751
2038
|
}
|
|
1752
2039
|
console.log("\nSwitch organization: waniwani org switch <name>");
|
|
@@ -1759,12 +2046,12 @@ var listCommand3 = new Command20("list").description("List your organizations").
|
|
|
1759
2046
|
|
|
1760
2047
|
// src/commands/org/switch.ts
|
|
1761
2048
|
import { Command as Command21 } from "commander";
|
|
1762
|
-
import
|
|
2049
|
+
import ora18 from "ora";
|
|
1763
2050
|
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
2051
|
const globalOptions = command.optsWithGlobals();
|
|
1765
2052
|
const json = globalOptions.json ?? false;
|
|
1766
2053
|
try {
|
|
1767
|
-
const spinner =
|
|
2054
|
+
const spinner = ora18("Fetching organizations...").start();
|
|
1768
2055
|
const { orgs } = await api.get("/api/oauth/orgs");
|
|
1769
2056
|
const org = orgs.find((o) => o.name === name || o.slug === name);
|
|
1770
2057
|
if (!org) {
|
|
@@ -1799,11 +2086,92 @@ var switchCommand = new Command21("switch").description("Switch to a different o
|
|
|
1799
2086
|
// src/commands/org/index.ts
|
|
1800
2087
|
var orgCommand = new Command22("org").description("Organization management commands").addCommand(listCommand3).addCommand(switchCommand);
|
|
1801
2088
|
|
|
1802
|
-
// src/commands/
|
|
1803
|
-
import
|
|
2089
|
+
// src/commands/push.ts
|
|
2090
|
+
import chalk13 from "chalk";
|
|
1804
2091
|
import { Command as Command23 } from "commander";
|
|
1805
|
-
import
|
|
1806
|
-
var
|
|
2092
|
+
import ora19 from "ora";
|
|
2093
|
+
var BATCH_SIZE2 = 50;
|
|
2094
|
+
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) => {
|
|
2095
|
+
const globalOptions = command.optsWithGlobals();
|
|
2096
|
+
const json = globalOptions.json ?? false;
|
|
2097
|
+
try {
|
|
2098
|
+
const cwd = process.cwd();
|
|
2099
|
+
const projectRoot = await findProjectRoot(cwd);
|
|
2100
|
+
if (!projectRoot) {
|
|
2101
|
+
throw new CLIError(
|
|
2102
|
+
"Not in a WaniWani project. Run 'waniwani init <name>' first.",
|
|
2103
|
+
"NOT_IN_PROJECT"
|
|
2104
|
+
);
|
|
2105
|
+
}
|
|
2106
|
+
const mcpId = await loadProjectMcpId(projectRoot);
|
|
2107
|
+
if (!mcpId) {
|
|
2108
|
+
throw new CLIError(
|
|
2109
|
+
"No MCP ID found in project config. Run 'waniwani init <name>' first.",
|
|
2110
|
+
"NO_MCP_ID"
|
|
2111
|
+
);
|
|
2112
|
+
}
|
|
2113
|
+
const spinner = ora19("Collecting files...").start();
|
|
2114
|
+
const files = await collectFiles(projectRoot);
|
|
2115
|
+
if (files.length === 0) {
|
|
2116
|
+
spinner.info("No files to sync");
|
|
2117
|
+
if (json) {
|
|
2118
|
+
formatOutput({ synced: 0, files: [] }, true);
|
|
2119
|
+
}
|
|
2120
|
+
return;
|
|
2121
|
+
}
|
|
2122
|
+
spinner.text = `Found ${files.length} files`;
|
|
2123
|
+
if (options.dryRun) {
|
|
2124
|
+
spinner.stop();
|
|
2125
|
+
console.log();
|
|
2126
|
+
console.log(chalk13.bold("Files that would be synced:"));
|
|
2127
|
+
for (const file of files) {
|
|
2128
|
+
console.log(` ${file.path}`);
|
|
2129
|
+
}
|
|
2130
|
+
console.log();
|
|
2131
|
+
console.log(`Total: ${files.length} files`);
|
|
2132
|
+
return;
|
|
2133
|
+
}
|
|
2134
|
+
const allWritten = [];
|
|
2135
|
+
const totalBatches = Math.ceil(files.length / BATCH_SIZE2);
|
|
2136
|
+
for (let i = 0; i < totalBatches; i++) {
|
|
2137
|
+
const batch = files.slice(i * BATCH_SIZE2, (i + 1) * BATCH_SIZE2);
|
|
2138
|
+
spinner.text = `Syncing files (${i + 1}/${totalBatches})...`;
|
|
2139
|
+
const result = await api.post(
|
|
2140
|
+
`/api/mcp/sandboxes/${mcpId}/files`,
|
|
2141
|
+
{
|
|
2142
|
+
files: batch.map((f) => ({
|
|
2143
|
+
path: f.path,
|
|
2144
|
+
content: f.content,
|
|
2145
|
+
encoding: f.encoding
|
|
2146
|
+
}))
|
|
2147
|
+
}
|
|
2148
|
+
);
|
|
2149
|
+
allWritten.push(...result.written);
|
|
2150
|
+
}
|
|
2151
|
+
spinner.succeed(`Synced ${allWritten.length} files`);
|
|
2152
|
+
if (json) {
|
|
2153
|
+
formatOutput(
|
|
2154
|
+
{
|
|
2155
|
+
synced: allWritten.length,
|
|
2156
|
+
files: allWritten
|
|
2157
|
+
},
|
|
2158
|
+
true
|
|
2159
|
+
);
|
|
2160
|
+
} else {
|
|
2161
|
+
console.log();
|
|
2162
|
+
formatSuccess(`${allWritten.length} files synced to sandbox`, false);
|
|
2163
|
+
}
|
|
2164
|
+
} catch (error) {
|
|
2165
|
+
handleError(error, json);
|
|
2166
|
+
process.exit(1);
|
|
2167
|
+
}
|
|
2168
|
+
});
|
|
2169
|
+
|
|
2170
|
+
// src/commands/task.ts
|
|
2171
|
+
import chalk14 from "chalk";
|
|
2172
|
+
import { Command as Command24 } from "commander";
|
|
2173
|
+
import ora20 from "ora";
|
|
2174
|
+
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
2175
|
const globalOptions = command.optsWithGlobals();
|
|
1808
2176
|
const json = globalOptions.json ?? false;
|
|
1809
2177
|
try {
|
|
@@ -1827,10 +2195,10 @@ var taskCommand = new Command23("task").description("Send a task to Claude runni
|
|
|
1827
2195
|
const maxSteps = options.maxSteps ? Number.parseInt(options.maxSteps, 10) : defaults.maxSteps;
|
|
1828
2196
|
if (!json) {
|
|
1829
2197
|
console.log();
|
|
1830
|
-
console.log(
|
|
2198
|
+
console.log(chalk14.bold("Task:"), prompt);
|
|
1831
2199
|
console.log();
|
|
1832
2200
|
}
|
|
1833
|
-
const spinner =
|
|
2201
|
+
const spinner = ora20("Starting task...").start();
|
|
1834
2202
|
const baseUrl = await api.getBaseUrl();
|
|
1835
2203
|
const response = await fetch(
|
|
1836
2204
|
`${baseUrl}/api/mcp/sandboxes/${mcpId}/task`,
|
|
@@ -1884,7 +2252,7 @@ var taskCommand = new Command23("task").description("Send a task to Claude runni
|
|
|
1884
2252
|
const event = parsed;
|
|
1885
2253
|
steps.push({ type: "text", text: event.content });
|
|
1886
2254
|
if (!json && event.content) {
|
|
1887
|
-
console.log(
|
|
2255
|
+
console.log(chalk14.white(event.content));
|
|
1888
2256
|
}
|
|
1889
2257
|
} else if (parsed.type === "tool_call") {
|
|
1890
2258
|
const event = parsed;
|
|
@@ -1895,24 +2263,24 @@ var taskCommand = new Command23("task").description("Send a task to Claude runni
|
|
|
1895
2263
|
output: event.output
|
|
1896
2264
|
});
|
|
1897
2265
|
if (!json) {
|
|
1898
|
-
console.log(
|
|
2266
|
+
console.log(chalk14.cyan(`> Using tool: ${event.tool}`));
|
|
1899
2267
|
if (event.input?.command) {
|
|
1900
|
-
console.log(
|
|
2268
|
+
console.log(chalk14.gray(` $ ${event.input.command}`));
|
|
1901
2269
|
}
|
|
1902
2270
|
if (event.output) {
|
|
1903
2271
|
const outputLines = event.output.split("\n");
|
|
1904
2272
|
if (outputLines.length > 10) {
|
|
1905
2273
|
console.log(
|
|
1906
|
-
|
|
2274
|
+
chalk14.gray(outputLines.slice(0, 5).join("\n"))
|
|
1907
2275
|
);
|
|
1908
2276
|
console.log(
|
|
1909
|
-
|
|
2277
|
+
chalk14.gray(
|
|
1910
2278
|
` ... (${outputLines.length - 10} more lines)`
|
|
1911
2279
|
)
|
|
1912
2280
|
);
|
|
1913
|
-
console.log(
|
|
2281
|
+
console.log(chalk14.gray(outputLines.slice(-5).join("\n")));
|
|
1914
2282
|
} else {
|
|
1915
|
-
console.log(
|
|
2283
|
+
console.log(chalk14.gray(event.output));
|
|
1916
2284
|
}
|
|
1917
2285
|
}
|
|
1918
2286
|
console.log();
|
|
@@ -1939,12 +2307,12 @@ var taskCommand = new Command23("task").description("Send a task to Claude runni
|
|
|
1939
2307
|
} else {
|
|
1940
2308
|
console.log();
|
|
1941
2309
|
console.log(
|
|
1942
|
-
|
|
2310
|
+
chalk14.green("\u2713"),
|
|
1943
2311
|
`Task completed in ${finalStepCount} steps.`
|
|
1944
2312
|
);
|
|
1945
2313
|
if (maxStepsReached) {
|
|
1946
2314
|
console.log(
|
|
1947
|
-
|
|
2315
|
+
chalk14.yellow("\u26A0"),
|
|
1948
2316
|
"Maximum steps reached. Task may be incomplete."
|
|
1949
2317
|
);
|
|
1950
2318
|
}
|
|
@@ -1957,10 +2325,12 @@ var taskCommand = new Command23("task").description("Send a task to Claude runni
|
|
|
1957
2325
|
|
|
1958
2326
|
// src/cli.ts
|
|
1959
2327
|
var version = "0.1.0";
|
|
1960
|
-
var program = new
|
|
2328
|
+
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
2329
|
program.addCommand(loginCommand);
|
|
1962
2330
|
program.addCommand(logoutCommand);
|
|
1963
2331
|
program.addCommand(initCommand);
|
|
2332
|
+
program.addCommand(pushCommand);
|
|
2333
|
+
program.addCommand(devCommand);
|
|
1964
2334
|
program.addCommand(mcpCommand);
|
|
1965
2335
|
program.addCommand(taskCommand);
|
|
1966
2336
|
program.addCommand(orgCommand);
|