@waniwani/cli 0.0.29 → 0.0.32
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 +286 -497
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,18 +3,13 @@
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { Command as Command25 } from "commander";
|
|
5
5
|
|
|
6
|
-
// src/commands/
|
|
7
|
-
import {
|
|
8
|
-
import chalk2 from "chalk";
|
|
9
|
-
import chokidar from "chokidar";
|
|
10
|
-
import { Command } from "commander";
|
|
11
|
-
import ora from "ora";
|
|
6
|
+
// src/commands/config/index.ts
|
|
7
|
+
import { Command as Command2 } from "commander";
|
|
12
8
|
|
|
13
|
-
// src/
|
|
14
|
-
import {
|
|
15
|
-
import { homedir as homedir2 } from "os";
|
|
9
|
+
// src/commands/config/init.ts
|
|
10
|
+
import { existsSync as existsSync2 } from "fs";
|
|
16
11
|
import { join as join2 } from "path";
|
|
17
|
-
import {
|
|
12
|
+
import { Command } from "commander";
|
|
18
13
|
|
|
19
14
|
// src/lib/config.ts
|
|
20
15
|
import { existsSync } from "fs";
|
|
@@ -22,13 +17,14 @@ import { mkdir, readFile, writeFile } from "fs/promises";
|
|
|
22
17
|
import { homedir } from "os";
|
|
23
18
|
import { join } from "path";
|
|
24
19
|
import { z } from "zod";
|
|
25
|
-
var
|
|
26
|
-
var
|
|
27
|
-
var
|
|
28
|
-
var
|
|
20
|
+
var LOCAL_CONFIG_DIR = ".waniwani";
|
|
21
|
+
var CONFIG_FILE_NAME = "settings.json";
|
|
22
|
+
var LOCAL_DIR = join(process.cwd(), LOCAL_CONFIG_DIR);
|
|
23
|
+
var LOCAL_FILE = join(LOCAL_DIR, CONFIG_FILE_NAME);
|
|
24
|
+
var GLOBAL_DIR = join(homedir(), LOCAL_CONFIG_DIR);
|
|
25
|
+
var GLOBAL_FILE = join(GLOBAL_DIR, CONFIG_FILE_NAME);
|
|
29
26
|
var DEFAULT_API_URL = "https://app.waniwani.ai";
|
|
30
27
|
var ConfigSchema = z.object({
|
|
31
|
-
defaults: z.object({ model: z.string(), maxSteps: z.number() }).default({ model: "claude-sonnet-4-20250514", maxSteps: 10 }),
|
|
32
28
|
mcpId: z.string().nullable().default(null),
|
|
33
29
|
apiUrl: z.string().nullable().default(null)
|
|
34
30
|
});
|
|
@@ -60,14 +56,6 @@ var Config = class {
|
|
|
60
56
|
await mkdir(this.dir, { recursive: true });
|
|
61
57
|
await writeFile(this.file, JSON.stringify(data, null, " "));
|
|
62
58
|
}
|
|
63
|
-
async getDefaults() {
|
|
64
|
-
return (await this.load()).defaults;
|
|
65
|
-
}
|
|
66
|
-
async setDefaults(defaults) {
|
|
67
|
-
const data = await this.load();
|
|
68
|
-
data.defaults = { ...data.defaults, ...defaults };
|
|
69
|
-
await this.save(data);
|
|
70
|
-
}
|
|
71
59
|
async getMcpId() {
|
|
72
60
|
return (await this.load()).mcpId;
|
|
73
61
|
}
|
|
@@ -91,10 +79,176 @@ var Config = class {
|
|
|
91
79
|
};
|
|
92
80
|
var config = new Config();
|
|
93
81
|
var globalConfig = new Config(true);
|
|
82
|
+
async function initConfigAt(dir, overrides = {}) {
|
|
83
|
+
const configDir = join(dir, LOCAL_CONFIG_DIR);
|
|
84
|
+
const configPath = join(configDir, CONFIG_FILE_NAME);
|
|
85
|
+
await mkdir(configDir, { recursive: true });
|
|
86
|
+
const data = ConfigSchema.parse(overrides);
|
|
87
|
+
await writeFile(configPath, JSON.stringify(data, null, " "), "utf-8");
|
|
88
|
+
return { path: configPath, config: data };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/lib/errors.ts
|
|
92
|
+
import chalk from "chalk";
|
|
93
|
+
import { ZodError } from "zod";
|
|
94
|
+
var CLIError = class extends Error {
|
|
95
|
+
constructor(message, code, details) {
|
|
96
|
+
super(message);
|
|
97
|
+
this.code = code;
|
|
98
|
+
this.details = details;
|
|
99
|
+
this.name = "CLIError";
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
var AuthError = class extends CLIError {
|
|
103
|
+
constructor(message, details) {
|
|
104
|
+
super(message, "AUTH_ERROR", details);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var McpError = class extends CLIError {
|
|
108
|
+
constructor(message, details) {
|
|
109
|
+
super(message, "MCP_ERROR", details);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
function handleError(error, json) {
|
|
113
|
+
if (error instanceof ZodError) {
|
|
114
|
+
const message = error.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
115
|
+
outputError("VALIDATION_ERROR", `Invalid input: ${message}`, json);
|
|
116
|
+
} else if (error instanceof CLIError) {
|
|
117
|
+
outputError(error.code, error.message, json, error.details);
|
|
118
|
+
} else if (error instanceof Error) {
|
|
119
|
+
outputError("UNKNOWN_ERROR", error.message, json);
|
|
120
|
+
} else {
|
|
121
|
+
outputError("UNKNOWN_ERROR", String(error), json);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function outputError(code, message, json, details) {
|
|
125
|
+
if (json) {
|
|
126
|
+
console.error(
|
|
127
|
+
JSON.stringify({ success: false, error: { code, message, details } })
|
|
128
|
+
);
|
|
129
|
+
} else {
|
|
130
|
+
console.error(chalk.red(`Error [${code}]:`), message);
|
|
131
|
+
if (details) {
|
|
132
|
+
console.error(chalk.gray("Details:"), JSON.stringify(details, null, 2));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/lib/output.ts
|
|
138
|
+
import chalk2 from "chalk";
|
|
139
|
+
function formatOutput(data, json) {
|
|
140
|
+
if (json) {
|
|
141
|
+
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
142
|
+
} else {
|
|
143
|
+
prettyPrint(data);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function formatSuccess(message, json) {
|
|
147
|
+
if (json) {
|
|
148
|
+
console.log(JSON.stringify({ success: true, message }));
|
|
149
|
+
} else {
|
|
150
|
+
console.log(chalk2.green("\u2713"), message);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function formatTable(headers, rows, json) {
|
|
154
|
+
if (json) {
|
|
155
|
+
const data = rows.map(
|
|
156
|
+
(row) => Object.fromEntries(headers.map((header, i) => [header, row[i]]))
|
|
157
|
+
);
|
|
158
|
+
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
159
|
+
} else {
|
|
160
|
+
const colWidths = headers.map(
|
|
161
|
+
(h, i) => Math.max(h.length, ...rows.map((r) => (r[i] || "").length))
|
|
162
|
+
);
|
|
163
|
+
const separator = colWidths.map((w) => "-".repeat(w + 2)).join("+");
|
|
164
|
+
const formatRow = (row) => row.map((cell, i) => ` ${(cell || "").padEnd(colWidths[i])} `).join("|");
|
|
165
|
+
console.log(chalk2.cyan(formatRow(headers)));
|
|
166
|
+
console.log(separator);
|
|
167
|
+
for (const row of rows) {
|
|
168
|
+
console.log(formatRow(row));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function formatList(items, json) {
|
|
173
|
+
if (json) {
|
|
174
|
+
const data = Object.fromEntries(
|
|
175
|
+
items.map((item) => [item.label, item.value])
|
|
176
|
+
);
|
|
177
|
+
console.log(JSON.stringify({ success: true, data }, null, 2));
|
|
178
|
+
} else {
|
|
179
|
+
const maxLabelLength = Math.max(...items.map((i) => i.label.length));
|
|
180
|
+
items.forEach((item) => {
|
|
181
|
+
console.log(
|
|
182
|
+
`${chalk2.gray(item.label.padEnd(maxLabelLength))} ${chalk2.white(item.value)}`
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function prettyPrint(data, indent = 0) {
|
|
188
|
+
const prefix = " ".repeat(indent);
|
|
189
|
+
if (Array.isArray(data)) {
|
|
190
|
+
data.forEach((item, index) => {
|
|
191
|
+
console.log(`${prefix}${chalk2.gray(`[${index}]`)}`);
|
|
192
|
+
prettyPrint(item, indent + 1);
|
|
193
|
+
});
|
|
194
|
+
} else if (typeof data === "object" && data !== null) {
|
|
195
|
+
for (const [key, value] of Object.entries(data)) {
|
|
196
|
+
if (typeof value === "object" && value !== null) {
|
|
197
|
+
console.log(`${prefix}${chalk2.gray(key)}:`);
|
|
198
|
+
prettyPrint(value, indent + 1);
|
|
199
|
+
} else {
|
|
200
|
+
console.log(
|
|
201
|
+
`${prefix}${chalk2.gray(key)}: ${chalk2.white(String(value))}`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
console.log(`${prefix}${chalk2.white(String(data))}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/commands/config/init.ts
|
|
211
|
+
var configInitCommand = new Command("init").description("Initialize .waniwani config in the current directory").option("--force", "Overwrite existing config").action(async (options, command) => {
|
|
212
|
+
const globalOptions = command.optsWithGlobals();
|
|
213
|
+
const json = globalOptions.json ?? false;
|
|
214
|
+
try {
|
|
215
|
+
const cwd = process.cwd();
|
|
216
|
+
const configPath = join2(cwd, LOCAL_CONFIG_DIR, CONFIG_FILE_NAME);
|
|
217
|
+
if (existsSync2(configPath) && !options.force) {
|
|
218
|
+
throw new CLIError(
|
|
219
|
+
`Config already exists at ${configPath}. Use --force to overwrite.`,
|
|
220
|
+
"CONFIG_EXISTS"
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
const result = await initConfigAt(cwd);
|
|
224
|
+
if (json) {
|
|
225
|
+
formatOutput({ created: result.path, config: result.config }, true);
|
|
226
|
+
} else {
|
|
227
|
+
formatSuccess(`Created ${result.path}`, false);
|
|
228
|
+
}
|
|
229
|
+
} catch (error) {
|
|
230
|
+
handleError(error, json);
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// src/commands/config/index.ts
|
|
236
|
+
var configCommand = new Command2("config").description("Manage WaniWani configuration").addCommand(configInitCommand);
|
|
237
|
+
|
|
238
|
+
// src/commands/dev.ts
|
|
239
|
+
import { relative as relative2 } from "path";
|
|
240
|
+
import chalk3 from "chalk";
|
|
241
|
+
import chokidar from "chokidar";
|
|
242
|
+
import { Command as Command3 } from "commander";
|
|
243
|
+
import ora from "ora";
|
|
94
244
|
|
|
95
245
|
// src/lib/auth.ts
|
|
96
|
-
|
|
97
|
-
|
|
246
|
+
import { access, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
247
|
+
import { homedir as homedir2 } from "os";
|
|
248
|
+
import { join as join3 } from "path";
|
|
249
|
+
import { z as z2 } from "zod";
|
|
250
|
+
var CONFIG_DIR = join3(homedir2(), ".waniwani");
|
|
251
|
+
var AUTH_FILE = join3(CONFIG_DIR, "auth.json");
|
|
98
252
|
var AuthStoreSchema = z2.object({
|
|
99
253
|
accessToken: z2.string().nullable().default(null),
|
|
100
254
|
refreshToken: z2.string().nullable().default(null),
|
|
@@ -196,57 +350,6 @@ var AuthManager = class {
|
|
|
196
350
|
};
|
|
197
351
|
var auth = new AuthManager();
|
|
198
352
|
|
|
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
353
|
// src/lib/api.ts
|
|
251
354
|
var ApiError = class extends CLIError {
|
|
252
355
|
constructor(message, code, statusCode, details) {
|
|
@@ -336,9 +439,9 @@ var api = {
|
|
|
336
439
|
};
|
|
337
440
|
|
|
338
441
|
// src/lib/sync.ts
|
|
339
|
-
import { existsSync as
|
|
442
|
+
import { existsSync as existsSync3 } from "fs";
|
|
340
443
|
import { mkdir as mkdir3, readdir, readFile as readFile3, stat, writeFile as writeFile3 } from "fs/promises";
|
|
341
|
-
import { dirname, join as
|
|
444
|
+
import { dirname, join as join4, relative } from "path";
|
|
342
445
|
import ignore from "ignore";
|
|
343
446
|
|
|
344
447
|
// src/lib/utils.ts
|
|
@@ -393,20 +496,20 @@ async function findProjectRoot(startDir) {
|
|
|
393
496
|
let current = startDir;
|
|
394
497
|
const root = dirname(current);
|
|
395
498
|
while (current !== root) {
|
|
396
|
-
if (
|
|
499
|
+
if (existsSync3(join4(current, PROJECT_DIR))) {
|
|
397
500
|
return current;
|
|
398
501
|
}
|
|
399
502
|
const parent = dirname(current);
|
|
400
503
|
if (parent === current) break;
|
|
401
504
|
current = parent;
|
|
402
505
|
}
|
|
403
|
-
if (
|
|
506
|
+
if (existsSync3(join4(current, PROJECT_DIR))) {
|
|
404
507
|
return current;
|
|
405
508
|
}
|
|
406
509
|
return null;
|
|
407
510
|
}
|
|
408
511
|
async function loadProjectMcpId(projectRoot) {
|
|
409
|
-
const settingsPath =
|
|
512
|
+
const settingsPath = join4(projectRoot, PROJECT_DIR, SETTINGS_FILE);
|
|
410
513
|
try {
|
|
411
514
|
const content = await readFile3(settingsPath, "utf-8");
|
|
412
515
|
const settings = JSON.parse(content);
|
|
@@ -434,8 +537,8 @@ var DEFAULT_IGNORE_PATTERNS = [
|
|
|
434
537
|
async function loadIgnorePatterns(projectRoot) {
|
|
435
538
|
const ig = ignore();
|
|
436
539
|
ig.add(DEFAULT_IGNORE_PATTERNS);
|
|
437
|
-
const gitignorePath =
|
|
438
|
-
if (
|
|
540
|
+
const gitignorePath = join4(projectRoot, ".gitignore");
|
|
541
|
+
if (existsSync3(gitignorePath)) {
|
|
439
542
|
try {
|
|
440
543
|
const content = await readFile3(gitignorePath, "utf-8");
|
|
441
544
|
ig.add(content);
|
|
@@ -450,7 +553,7 @@ async function collectFiles(projectRoot) {
|
|
|
450
553
|
async function walk(dir) {
|
|
451
554
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
452
555
|
for (const entry of entries) {
|
|
453
|
-
const fullPath =
|
|
556
|
+
const fullPath = join4(dir, entry.name);
|
|
454
557
|
const relativePath = relative(projectRoot, fullPath);
|
|
455
558
|
if (ig.ignores(relativePath)) {
|
|
456
559
|
continue;
|
|
@@ -480,7 +583,7 @@ async function pullFilesFromSandbox(mcpId, targetDir) {
|
|
|
480
583
|
);
|
|
481
584
|
const writtenFiles = [];
|
|
482
585
|
for (const file of result.files) {
|
|
483
|
-
const localPath =
|
|
586
|
+
const localPath = join4(targetDir, file.path);
|
|
484
587
|
const dir = dirname(localPath);
|
|
485
588
|
await mkdir3(dir, { recursive: true });
|
|
486
589
|
if (file.encoding === "base64") {
|
|
@@ -493,9 +596,9 @@ async function pullFilesFromSandbox(mcpId, targetDir) {
|
|
|
493
596
|
return { count: writtenFiles.length, files: writtenFiles };
|
|
494
597
|
}
|
|
495
598
|
async function collectSingleFile(projectRoot, filePath) {
|
|
496
|
-
const fullPath =
|
|
599
|
+
const fullPath = join4(projectRoot, filePath);
|
|
497
600
|
const relativePath = relative(projectRoot, fullPath);
|
|
498
|
-
if (!
|
|
601
|
+
if (!existsSync3(fullPath)) {
|
|
499
602
|
return null;
|
|
500
603
|
}
|
|
501
604
|
try {
|
|
@@ -518,7 +621,7 @@ async function collectSingleFile(projectRoot, filePath) {
|
|
|
518
621
|
// src/commands/dev.ts
|
|
519
622
|
var BATCH_SIZE = 50;
|
|
520
623
|
var DEFAULT_DEBOUNCE_MS = 300;
|
|
521
|
-
var devCommand = new
|
|
624
|
+
var devCommand = new Command3("dev").description("Watch and sync files to MCP sandbox").option("--no-initial-sync", "Skip initial sync of all files").option(
|
|
522
625
|
"--debounce <ms>",
|
|
523
626
|
"Debounce delay in milliseconds",
|
|
524
627
|
String(DEFAULT_DEBOUNCE_MS)
|
|
@@ -576,7 +679,7 @@ var devCommand = new Command("dev").description("Watch and sync files to MCP san
|
|
|
576
679
|
}
|
|
577
680
|
const file = await collectSingleFile(projectRoot, relativePath);
|
|
578
681
|
if (!file) {
|
|
579
|
-
console.log(
|
|
682
|
+
console.log(chalk3.yellow("Skipped:"), relativePath);
|
|
580
683
|
return;
|
|
581
684
|
}
|
|
582
685
|
try {
|
|
@@ -592,17 +695,17 @@ var devCommand = new Command("dev").description("Watch and sync files to MCP san
|
|
|
592
695
|
]
|
|
593
696
|
}
|
|
594
697
|
);
|
|
595
|
-
console.log(
|
|
698
|
+
console.log(chalk3.green("Synced:"), relativePath);
|
|
596
699
|
} catch (error) {
|
|
597
|
-
console.log(
|
|
700
|
+
console.log(chalk3.red("Failed:"), relativePath);
|
|
598
701
|
if (globalOptions.verbose) {
|
|
599
702
|
console.error(error);
|
|
600
703
|
}
|
|
601
704
|
}
|
|
602
705
|
}, debounceMs);
|
|
603
706
|
console.log();
|
|
604
|
-
console.log(
|
|
605
|
-
console.log(
|
|
707
|
+
console.log(chalk3.bold("Watching for changes..."));
|
|
708
|
+
console.log(chalk3.dim("Press Ctrl+C to stop"));
|
|
606
709
|
console.log();
|
|
607
710
|
const watcher = chokidar.watch(projectRoot, {
|
|
608
711
|
ignored: (path) => {
|
|
@@ -618,11 +721,11 @@ var devCommand = new Command("dev").description("Watch and sync files to MCP san
|
|
|
618
721
|
});
|
|
619
722
|
watcher.on("add", (path) => syncFile(path)).on("change", (path) => syncFile(path)).on("unlink", (path) => {
|
|
620
723
|
const relativePath = relative2(projectRoot, path);
|
|
621
|
-
console.log(
|
|
724
|
+
console.log(chalk3.yellow("Deleted (local only):"), relativePath);
|
|
622
725
|
});
|
|
623
726
|
const cleanup = () => {
|
|
624
727
|
console.log();
|
|
625
|
-
console.log(
|
|
728
|
+
console.log(chalk3.dim("Stopping watcher..."));
|
|
626
729
|
watcher.close().then(() => {
|
|
627
730
|
process.exit(0);
|
|
628
731
|
});
|
|
@@ -636,95 +739,32 @@ var devCommand = new Command("dev").description("Watch and sync files to MCP san
|
|
|
636
739
|
});
|
|
637
740
|
|
|
638
741
|
// src/commands/init.ts
|
|
639
|
-
import { existsSync as
|
|
640
|
-
import { mkdir as mkdir4,
|
|
641
|
-
import { join as
|
|
642
|
-
import { Command as
|
|
742
|
+
import { existsSync as existsSync4 } from "fs";
|
|
743
|
+
import { mkdir as mkdir4, readFile as readFile4 } from "fs/promises";
|
|
744
|
+
import { join as join5 } from "path";
|
|
745
|
+
import { Command as Command4 } from "commander";
|
|
643
746
|
import ora2 from "ora";
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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
|
-
});
|
|
747
|
+
async function loadParentConfig(cwd) {
|
|
748
|
+
const parentConfigPath = join5(cwd, LOCAL_CONFIG_DIR, CONFIG_FILE_NAME);
|
|
749
|
+
if (!existsSync4(parentConfigPath)) {
|
|
750
|
+
return null;
|
|
693
751
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
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))}`);
|
|
752
|
+
try {
|
|
753
|
+
const content = await readFile4(parentConfigPath, "utf-8");
|
|
754
|
+
const config2 = JSON.parse(content);
|
|
755
|
+
const { mcpId: _, ...rest } = config2;
|
|
756
|
+
return rest;
|
|
757
|
+
} catch {
|
|
758
|
+
return null;
|
|
715
759
|
}
|
|
716
760
|
}
|
|
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) => {
|
|
761
|
+
var initCommand = new Command4("init").description("Create a new MCP project from template").argument("<name>", "Name for the MCP project").action(async (name, _, command) => {
|
|
722
762
|
const globalOptions = command.optsWithGlobals();
|
|
723
763
|
const json = globalOptions.json ?? false;
|
|
724
764
|
try {
|
|
725
765
|
const cwd = process.cwd();
|
|
726
|
-
const projectDir =
|
|
727
|
-
if (
|
|
766
|
+
const projectDir = join5(cwd, name);
|
|
767
|
+
if (existsSync4(projectDir)) {
|
|
728
768
|
if (json) {
|
|
729
769
|
formatOutput(
|
|
730
770
|
{
|
|
@@ -746,21 +786,12 @@ var initCommand = new Command2("init").description("Create a new MCP project fro
|
|
|
746
786
|
await mkdir4(projectDir, { recursive: true });
|
|
747
787
|
await pullFilesFromSandbox(result.id, projectDir);
|
|
748
788
|
spinner.text = "Setting up project config...";
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
mcpId
|
|
754
|
-
|
|
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
|
-
);
|
|
789
|
+
const parentConfig = await loadParentConfig(cwd);
|
|
790
|
+
await initConfigAt(projectDir, {
|
|
791
|
+
...parentConfig,
|
|
792
|
+
mcpId: result.id
|
|
793
|
+
// Always use the new sandbox's mcpId
|
|
794
|
+
});
|
|
764
795
|
spinner.succeed("MCP project created");
|
|
765
796
|
if (json) {
|
|
766
797
|
formatOutput(
|
|
@@ -797,7 +828,7 @@ var initCommand = new Command2("init").description("Create a new MCP project fro
|
|
|
797
828
|
import { spawn } from "child_process";
|
|
798
829
|
import { createServer } from "http";
|
|
799
830
|
import chalk4 from "chalk";
|
|
800
|
-
import { Command as
|
|
831
|
+
import { Command as Command5 } from "commander";
|
|
801
832
|
import ora3 from "ora";
|
|
802
833
|
var CALLBACK_PORT = 54321;
|
|
803
834
|
var CALLBACK_URL = `http://localhost:${CALLBACK_PORT}/callback`;
|
|
@@ -1073,7 +1104,7 @@ async function exchangeCodeForToken(code, codeVerifier, clientId, resource) {
|
|
|
1073
1104
|
}
|
|
1074
1105
|
return response.json();
|
|
1075
1106
|
}
|
|
1076
|
-
var loginCommand = new
|
|
1107
|
+
var loginCommand = new Command5("login").description("Log in to WaniWani").option("--no-browser", "Don't open the browser automatically").action(async (options, command) => {
|
|
1077
1108
|
const globalOptions = command.optsWithGlobals();
|
|
1078
1109
|
const json = globalOptions.json ?? false;
|
|
1079
1110
|
try {
|
|
@@ -1178,8 +1209,8 @@ var loginCommand = new Command3("login").description("Log in to WaniWani").optio
|
|
|
1178
1209
|
});
|
|
1179
1210
|
|
|
1180
1211
|
// src/commands/logout.ts
|
|
1181
|
-
import { Command as
|
|
1182
|
-
var logoutCommand = new
|
|
1212
|
+
import { Command as Command6 } from "commander";
|
|
1213
|
+
var logoutCommand = new Command6("logout").description("Log out from WaniWani").action(async (_, command) => {
|
|
1183
1214
|
const globalOptions = command.optsWithGlobals();
|
|
1184
1215
|
const json = globalOptions.json ?? false;
|
|
1185
1216
|
try {
|
|
@@ -1204,12 +1235,12 @@ var logoutCommand = new Command4("logout").description("Log out from WaniWani").
|
|
|
1204
1235
|
});
|
|
1205
1236
|
|
|
1206
1237
|
// src/commands/mcp/index.ts
|
|
1207
|
-
import { Command as
|
|
1238
|
+
import { Command as Command20 } from "commander";
|
|
1208
1239
|
|
|
1209
1240
|
// src/commands/mcp/delete.ts
|
|
1210
|
-
import { Command as
|
|
1241
|
+
import { Command as Command7 } from "commander";
|
|
1211
1242
|
import ora4 from "ora";
|
|
1212
|
-
var deleteCommand = new
|
|
1243
|
+
var deleteCommand = new Command7("delete").description("Delete the MCP sandbox").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1213
1244
|
const globalOptions = command.optsWithGlobals();
|
|
1214
1245
|
const json = globalOptions.json ?? false;
|
|
1215
1246
|
try {
|
|
@@ -1238,9 +1269,9 @@ var deleteCommand = new Command5("delete").description("Delete the MCP sandbox")
|
|
|
1238
1269
|
});
|
|
1239
1270
|
|
|
1240
1271
|
// src/commands/mcp/deploy.ts
|
|
1241
|
-
import { Command as
|
|
1272
|
+
import { Command as Command8 } from "commander";
|
|
1242
1273
|
import ora5 from "ora";
|
|
1243
|
-
var deployCommand = new
|
|
1274
|
+
var deployCommand = new Command8("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) => {
|
|
1244
1275
|
const globalOptions = command.optsWithGlobals();
|
|
1245
1276
|
const json = globalOptions.json ?? false;
|
|
1246
1277
|
try {
|
|
@@ -1285,13 +1316,13 @@ var deployCommand = new Command6("deploy").description("Deploy MCP server to Git
|
|
|
1285
1316
|
});
|
|
1286
1317
|
|
|
1287
1318
|
// src/commands/mcp/file/index.ts
|
|
1288
|
-
import { Command as
|
|
1319
|
+
import { Command as Command12 } from "commander";
|
|
1289
1320
|
|
|
1290
1321
|
// src/commands/mcp/file/list.ts
|
|
1291
1322
|
import chalk5 from "chalk";
|
|
1292
|
-
import { Command as
|
|
1323
|
+
import { Command as Command9 } from "commander";
|
|
1293
1324
|
import ora6 from "ora";
|
|
1294
|
-
var listCommand = new
|
|
1325
|
+
var listCommand = new Command9("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) => {
|
|
1295
1326
|
const globalOptions = command.optsWithGlobals();
|
|
1296
1327
|
const json = globalOptions.json ?? false;
|
|
1297
1328
|
try {
|
|
@@ -1340,10 +1371,10 @@ function formatSize(bytes) {
|
|
|
1340
1371
|
}
|
|
1341
1372
|
|
|
1342
1373
|
// src/commands/mcp/file/read.ts
|
|
1343
|
-
import { writeFile as
|
|
1344
|
-
import { Command as
|
|
1374
|
+
import { writeFile as writeFile4 } from "fs/promises";
|
|
1375
|
+
import { Command as Command10 } from "commander";
|
|
1345
1376
|
import ora7 from "ora";
|
|
1346
|
-
var readCommand = new
|
|
1377
|
+
var readCommand = new Command10("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) => {
|
|
1347
1378
|
const globalOptions = command.optsWithGlobals();
|
|
1348
1379
|
const json = globalOptions.json ?? false;
|
|
1349
1380
|
try {
|
|
@@ -1367,7 +1398,7 @@ var readCommand = new Command8("read").description("Read a file from the MCP san
|
|
|
1367
1398
|
}
|
|
1368
1399
|
if (options.output) {
|
|
1369
1400
|
const buffer = result.encoding === "base64" ? Buffer.from(result.content, "base64") : Buffer.from(result.content, "utf8");
|
|
1370
|
-
await
|
|
1401
|
+
await writeFile4(options.output, buffer);
|
|
1371
1402
|
if (json) {
|
|
1372
1403
|
formatOutput({ path, savedTo: options.output }, true);
|
|
1373
1404
|
} else {
|
|
@@ -1388,10 +1419,10 @@ var readCommand = new Command8("read").description("Read a file from the MCP san
|
|
|
1388
1419
|
});
|
|
1389
1420
|
|
|
1390
1421
|
// src/commands/mcp/file/write.ts
|
|
1391
|
-
import { readFile as
|
|
1392
|
-
import { Command as
|
|
1422
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
1423
|
+
import { Command as Command11 } from "commander";
|
|
1393
1424
|
import ora8 from "ora";
|
|
1394
|
-
var writeCommand = new
|
|
1425
|
+
var writeCommand = new Command11("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) => {
|
|
1395
1426
|
const globalOptions = command.optsWithGlobals();
|
|
1396
1427
|
const json = globalOptions.json ?? false;
|
|
1397
1428
|
try {
|
|
@@ -1412,7 +1443,7 @@ var writeCommand = new Command9("write").description("Write a file to the MCP sa
|
|
|
1412
1443
|
encoding = "base64";
|
|
1413
1444
|
}
|
|
1414
1445
|
} else if (options.file) {
|
|
1415
|
-
const fileBuffer = await
|
|
1446
|
+
const fileBuffer = await readFile5(options.file);
|
|
1416
1447
|
if (options.base64) {
|
|
1417
1448
|
content = fileBuffer.toString("base64");
|
|
1418
1449
|
encoding = "base64";
|
|
@@ -1445,13 +1476,13 @@ var writeCommand = new Command9("write").description("Write a file to the MCP sa
|
|
|
1445
1476
|
});
|
|
1446
1477
|
|
|
1447
1478
|
// src/commands/mcp/file/index.ts
|
|
1448
|
-
var fileCommand = new
|
|
1479
|
+
var fileCommand = new Command12("file").description("File operations in MCP sandbox").addCommand(readCommand).addCommand(writeCommand).addCommand(listCommand);
|
|
1449
1480
|
|
|
1450
1481
|
// src/commands/mcp/list.ts
|
|
1451
1482
|
import chalk6 from "chalk";
|
|
1452
|
-
import { Command as
|
|
1483
|
+
import { Command as Command13 } from "commander";
|
|
1453
1484
|
import ora9 from "ora";
|
|
1454
|
-
var listCommand2 = new
|
|
1485
|
+
var listCommand2 = new Command13("list").description("List all MCPs in your organization").option("--all", "Include stopped/expired MCPs").action(async (options, command) => {
|
|
1455
1486
|
const globalOptions = command.optsWithGlobals();
|
|
1456
1487
|
const json = globalOptions.json ?? false;
|
|
1457
1488
|
try {
|
|
@@ -1509,9 +1540,9 @@ var listCommand2 = new Command11("list").description("List all MCPs in your orga
|
|
|
1509
1540
|
|
|
1510
1541
|
// src/commands/mcp/logs.ts
|
|
1511
1542
|
import chalk7 from "chalk";
|
|
1512
|
-
import { Command as
|
|
1543
|
+
import { Command as Command14 } from "commander";
|
|
1513
1544
|
import ora10 from "ora";
|
|
1514
|
-
var logsCommand = new
|
|
1545
|
+
var logsCommand = new Command14("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) => {
|
|
1515
1546
|
const globalOptions = command.optsWithGlobals();
|
|
1516
1547
|
const json = globalOptions.json ?? false;
|
|
1517
1548
|
let reader;
|
|
@@ -1659,9 +1690,9 @@ Error: ${event.error}`));
|
|
|
1659
1690
|
|
|
1660
1691
|
// src/commands/mcp/run-command.ts
|
|
1661
1692
|
import chalk8 from "chalk";
|
|
1662
|
-
import { Command as
|
|
1693
|
+
import { Command as Command15 } from "commander";
|
|
1663
1694
|
import ora11 from "ora";
|
|
1664
|
-
var runCommandCommand = new
|
|
1695
|
+
var runCommandCommand = new Command15("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(
|
|
1665
1696
|
"--timeout <ms>",
|
|
1666
1697
|
"Command timeout in milliseconds (default: 30000, max: 300000)"
|
|
1667
1698
|
).action(async (cmd, args, options, command) => {
|
|
@@ -1725,9 +1756,9 @@ var runCommandCommand = new Command13("run-command").description("Run a command
|
|
|
1725
1756
|
|
|
1726
1757
|
// src/commands/mcp/start.ts
|
|
1727
1758
|
import chalk9 from "chalk";
|
|
1728
|
-
import { Command as
|
|
1759
|
+
import { Command as Command16 } from "commander";
|
|
1729
1760
|
import ora12 from "ora";
|
|
1730
|
-
var startCommand = new
|
|
1761
|
+
var startCommand = new Command16("start").description("Start the MCP server (npm run dev)").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1731
1762
|
const globalOptions = command.optsWithGlobals();
|
|
1732
1763
|
const json = globalOptions.json ?? false;
|
|
1733
1764
|
try {
|
|
@@ -1758,6 +1789,11 @@ var startCommand = new Command14("start").description("Start the MCP server (npm
|
|
|
1758
1789
|
false
|
|
1759
1790
|
);
|
|
1760
1791
|
console.log();
|
|
1792
|
+
console.log(chalk9.bold("Test with MCP Inspector:"));
|
|
1793
|
+
console.log(
|
|
1794
|
+
` npx @modelcontextprotocol/inspector --url ${result.previewUrl}`
|
|
1795
|
+
);
|
|
1796
|
+
console.log();
|
|
1761
1797
|
console.log(
|
|
1762
1798
|
chalk9.gray("Run 'waniwani mcp logs' to stream server output")
|
|
1763
1799
|
);
|
|
@@ -1770,9 +1806,9 @@ var startCommand = new Command14("start").description("Start the MCP server (npm
|
|
|
1770
1806
|
|
|
1771
1807
|
// src/commands/mcp/status.ts
|
|
1772
1808
|
import chalk10 from "chalk";
|
|
1773
|
-
import { Command as
|
|
1809
|
+
import { Command as Command17 } from "commander";
|
|
1774
1810
|
import ora13 from "ora";
|
|
1775
|
-
var statusCommand = new
|
|
1811
|
+
var statusCommand = new Command17("status").description("Show current MCP sandbox status").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1776
1812
|
const globalOptions = command.optsWithGlobals();
|
|
1777
1813
|
const json = globalOptions.json ?? false;
|
|
1778
1814
|
try {
|
|
@@ -1828,9 +1864,9 @@ var statusCommand = new Command15("status").description("Show current MCP sandbo
|
|
|
1828
1864
|
});
|
|
1829
1865
|
|
|
1830
1866
|
// src/commands/mcp/stop.ts
|
|
1831
|
-
import { Command as
|
|
1867
|
+
import { Command as Command18 } from "commander";
|
|
1832
1868
|
import ora14 from "ora";
|
|
1833
|
-
var stopCommand = new
|
|
1869
|
+
var stopCommand = new Command18("stop").description("Stop the MCP server process").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
|
|
1834
1870
|
const globalOptions = command.optsWithGlobals();
|
|
1835
1871
|
const json = globalOptions.json ?? false;
|
|
1836
1872
|
try {
|
|
@@ -1864,105 +1900,14 @@ var stopCommand = new Command16("stop").description("Stop the MCP server process
|
|
|
1864
1900
|
}
|
|
1865
1901
|
});
|
|
1866
1902
|
|
|
1867
|
-
// src/commands/mcp/test.ts
|
|
1868
|
-
import chalk11 from "chalk";
|
|
1869
|
-
import { Command as Command17 } from "commander";
|
|
1870
|
-
import ora15 from "ora";
|
|
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(
|
|
1872
|
-
async (tool, args, options, command) => {
|
|
1873
|
-
const globalOptions = command.optsWithGlobals();
|
|
1874
|
-
const json = globalOptions.json ?? false;
|
|
1875
|
-
try {
|
|
1876
|
-
let mcpId = options.mcpId;
|
|
1877
|
-
if (!mcpId) {
|
|
1878
|
-
mcpId = await config.getMcpId();
|
|
1879
|
-
if (!mcpId) {
|
|
1880
|
-
throw new McpError(
|
|
1881
|
-
"No active MCP. Run 'waniwani mcp create <name>' or 'waniwani mcp use <name>'."
|
|
1882
|
-
);
|
|
1883
|
-
}
|
|
1884
|
-
}
|
|
1885
|
-
if (!tool) {
|
|
1886
|
-
const spinner = ora15("Fetching available tools...").start();
|
|
1887
|
-
const result = await api.post(
|
|
1888
|
-
`/api/mcp/sandboxes/${mcpId}/test`,
|
|
1889
|
-
{ action: "list" }
|
|
1890
|
-
);
|
|
1891
|
-
spinner.stop();
|
|
1892
|
-
const tools = result.tools;
|
|
1893
|
-
if (json) {
|
|
1894
|
-
formatOutput({ tools }, true);
|
|
1895
|
-
} else {
|
|
1896
|
-
if (tools.length === 0) {
|
|
1897
|
-
console.log("No tools available.");
|
|
1898
|
-
} else {
|
|
1899
|
-
console.log(chalk11.bold("\nAvailable Tools:\n"));
|
|
1900
|
-
formatTable(
|
|
1901
|
-
["Name", "Description"],
|
|
1902
|
-
tools.map((t) => [t.name, t.description || "No description"]),
|
|
1903
|
-
false
|
|
1904
|
-
);
|
|
1905
|
-
console.log(
|
|
1906
|
-
`
|
|
1907
|
-
Test a tool: waniwani mcp test <tool-name> '{"arg": "value"}'`
|
|
1908
|
-
);
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
} else {
|
|
1912
|
-
let toolArgs = {};
|
|
1913
|
-
if (args.length > 0) {
|
|
1914
|
-
try {
|
|
1915
|
-
toolArgs = JSON.parse(args.join(" "));
|
|
1916
|
-
} catch {
|
|
1917
|
-
throw new SandboxError(
|
|
1918
|
-
`Invalid JSON arguments. Expected format: '{"key": "value"}'`
|
|
1919
|
-
);
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
const spinner = ora15(`Calling tool "${tool}"...`).start();
|
|
1923
|
-
const startTime = Date.now();
|
|
1924
|
-
const result = await api.post(
|
|
1925
|
-
`/api/mcp/sandboxes/${mcpId}/test`,
|
|
1926
|
-
{
|
|
1927
|
-
action: "call",
|
|
1928
|
-
tool,
|
|
1929
|
-
args: toolArgs
|
|
1930
|
-
}
|
|
1931
|
-
);
|
|
1932
|
-
const duration = result.duration || Date.now() - startTime;
|
|
1933
|
-
spinner.stop();
|
|
1934
|
-
const output = {
|
|
1935
|
-
tool,
|
|
1936
|
-
input: toolArgs,
|
|
1937
|
-
result: result.result,
|
|
1938
|
-
duration
|
|
1939
|
-
};
|
|
1940
|
-
if (json) {
|
|
1941
|
-
formatOutput(output, true);
|
|
1942
|
-
} else {
|
|
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:"));
|
|
1948
|
-
console.log(JSON.stringify(result.result, null, 2));
|
|
1949
|
-
}
|
|
1950
|
-
}
|
|
1951
|
-
} catch (error) {
|
|
1952
|
-
handleError(error, json);
|
|
1953
|
-
process.exit(1);
|
|
1954
|
-
}
|
|
1955
|
-
}
|
|
1956
|
-
);
|
|
1957
|
-
|
|
1958
1903
|
// src/commands/mcp/use.ts
|
|
1959
|
-
import { Command as
|
|
1960
|
-
import
|
|
1961
|
-
var useCommand = new
|
|
1904
|
+
import { Command as Command19 } from "commander";
|
|
1905
|
+
import ora15 from "ora";
|
|
1906
|
+
var useCommand = new Command19("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) => {
|
|
1962
1907
|
const globalOptions = command.optsWithGlobals();
|
|
1963
1908
|
const json = globalOptions.json ?? false;
|
|
1964
1909
|
try {
|
|
1965
|
-
const spinner =
|
|
1910
|
+
const spinner = ora15("Fetching MCPs...").start();
|
|
1966
1911
|
const mcps = await api.get("/api/admin/mcps");
|
|
1967
1912
|
spinner.stop();
|
|
1968
1913
|
const mcp = mcps.find((m) => m.name === name);
|
|
@@ -1998,20 +1943,20 @@ var useCommand = new Command18("use").description("Select an MCP to use for subs
|
|
|
1998
1943
|
});
|
|
1999
1944
|
|
|
2000
1945
|
// src/commands/mcp/index.ts
|
|
2001
|
-
var mcpCommand = new
|
|
1946
|
+
var mcpCommand = new Command20("mcp").description("MCP sandbox management commands").addCommand(listCommand2).addCommand(useCommand).addCommand(statusCommand).addCommand(startCommand).addCommand(stopCommand).addCommand(logsCommand).addCommand(deleteCommand).addCommand(deployCommand).addCommand(fileCommand).addCommand(runCommandCommand);
|
|
2002
1947
|
|
|
2003
1948
|
// src/commands/org/index.ts
|
|
2004
|
-
import { Command as
|
|
1949
|
+
import { Command as Command23 } from "commander";
|
|
2005
1950
|
|
|
2006
1951
|
// src/commands/org/list.ts
|
|
2007
|
-
import
|
|
2008
|
-
import { Command as
|
|
2009
|
-
import
|
|
2010
|
-
var listCommand3 = new
|
|
1952
|
+
import chalk11 from "chalk";
|
|
1953
|
+
import { Command as Command21 } from "commander";
|
|
1954
|
+
import ora16 from "ora";
|
|
1955
|
+
var listCommand3 = new Command21("list").description("List your organizations").action(async (_, command) => {
|
|
2011
1956
|
const globalOptions = command.optsWithGlobals();
|
|
2012
1957
|
const json = globalOptions.json ?? false;
|
|
2013
1958
|
try {
|
|
2014
|
-
const spinner =
|
|
1959
|
+
const spinner = ora16("Fetching organizations...").start();
|
|
2015
1960
|
const result = await api.get("/api/oauth/orgs");
|
|
2016
1961
|
spinner.stop();
|
|
2017
1962
|
const { orgs, activeOrgId } = result;
|
|
@@ -2031,11 +1976,11 @@ var listCommand3 = new Command20("list").description("List your organizations").
|
|
|
2031
1976
|
console.log("No organizations found.");
|
|
2032
1977
|
return;
|
|
2033
1978
|
}
|
|
2034
|
-
console.log(
|
|
1979
|
+
console.log(chalk11.bold("\nOrganizations:\n"));
|
|
2035
1980
|
const rows = orgs.map((o) => {
|
|
2036
1981
|
const isActive = o.id === activeOrgId;
|
|
2037
1982
|
return [
|
|
2038
|
-
isActive ?
|
|
1983
|
+
isActive ? chalk11.cyan(`* ${o.name}`) : ` ${o.name}`,
|
|
2039
1984
|
o.slug,
|
|
2040
1985
|
o.role
|
|
2041
1986
|
];
|
|
@@ -2045,7 +1990,7 @@ var listCommand3 = new Command20("list").description("List your organizations").
|
|
|
2045
1990
|
if (activeOrgId) {
|
|
2046
1991
|
const activeOrg = orgs.find((o) => o.id === activeOrgId);
|
|
2047
1992
|
if (activeOrg) {
|
|
2048
|
-
console.log(`Active organization: ${
|
|
1993
|
+
console.log(`Active organization: ${chalk11.cyan(activeOrg.name)}`);
|
|
2049
1994
|
}
|
|
2050
1995
|
}
|
|
2051
1996
|
console.log("\nSwitch organization: waniwani org switch <name>");
|
|
@@ -2057,13 +2002,13 @@ var listCommand3 = new Command20("list").description("List your organizations").
|
|
|
2057
2002
|
});
|
|
2058
2003
|
|
|
2059
2004
|
// src/commands/org/switch.ts
|
|
2060
|
-
import { Command as
|
|
2061
|
-
import
|
|
2062
|
-
var switchCommand = new
|
|
2005
|
+
import { Command as Command22 } from "commander";
|
|
2006
|
+
import ora17 from "ora";
|
|
2007
|
+
var switchCommand = new Command22("switch").description("Switch to a different organization").argument("<name>", "Name or slug of the organization to switch to").action(async (name, _, command) => {
|
|
2063
2008
|
const globalOptions = command.optsWithGlobals();
|
|
2064
2009
|
const json = globalOptions.json ?? false;
|
|
2065
2010
|
try {
|
|
2066
|
-
const spinner =
|
|
2011
|
+
const spinner = ora17("Fetching organizations...").start();
|
|
2067
2012
|
const { orgs } = await api.get("/api/oauth/orgs");
|
|
2068
2013
|
const org = orgs.find((o) => o.name === name || o.slug === name);
|
|
2069
2014
|
if (!org) {
|
|
@@ -2096,14 +2041,14 @@ var switchCommand = new Command21("switch").description("Switch to a different o
|
|
|
2096
2041
|
});
|
|
2097
2042
|
|
|
2098
2043
|
// src/commands/org/index.ts
|
|
2099
|
-
var orgCommand = new
|
|
2044
|
+
var orgCommand = new Command23("org").description("Organization management commands").addCommand(listCommand3).addCommand(switchCommand);
|
|
2100
2045
|
|
|
2101
2046
|
// src/commands/push.ts
|
|
2102
|
-
import
|
|
2103
|
-
import { Command as
|
|
2104
|
-
import
|
|
2047
|
+
import chalk12 from "chalk";
|
|
2048
|
+
import { Command as Command24 } from "commander";
|
|
2049
|
+
import ora18 from "ora";
|
|
2105
2050
|
var BATCH_SIZE2 = 50;
|
|
2106
|
-
var pushCommand = new
|
|
2051
|
+
var pushCommand = new Command24("push").description("Sync local files to MCP sandbox").option("--dry-run", "Show what would be synced without uploading").action(async (options, command) => {
|
|
2107
2052
|
const globalOptions = command.optsWithGlobals();
|
|
2108
2053
|
const json = globalOptions.json ?? false;
|
|
2109
2054
|
try {
|
|
@@ -2122,7 +2067,7 @@ var pushCommand = new Command23("push").description("Sync local files to MCP san
|
|
|
2122
2067
|
"NO_MCP_ID"
|
|
2123
2068
|
);
|
|
2124
2069
|
}
|
|
2125
|
-
const spinner =
|
|
2070
|
+
const spinner = ora18("Collecting files...").start();
|
|
2126
2071
|
const files = await collectFiles(projectRoot);
|
|
2127
2072
|
if (files.length === 0) {
|
|
2128
2073
|
spinner.info("No files to sync");
|
|
@@ -2135,7 +2080,7 @@ var pushCommand = new Command23("push").description("Sync local files to MCP san
|
|
|
2135
2080
|
if (options.dryRun) {
|
|
2136
2081
|
spinner.stop();
|
|
2137
2082
|
console.log();
|
|
2138
|
-
console.log(
|
|
2083
|
+
console.log(chalk12.bold("Files that would be synced:"));
|
|
2139
2084
|
for (const file of files) {
|
|
2140
2085
|
console.log(` ${file.path}`);
|
|
2141
2086
|
}
|
|
@@ -2179,162 +2124,6 @@ var pushCommand = new Command23("push").description("Sync local files to MCP san
|
|
|
2179
2124
|
}
|
|
2180
2125
|
});
|
|
2181
2126
|
|
|
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) => {
|
|
2187
|
-
const globalOptions = command.optsWithGlobals();
|
|
2188
|
-
const json = globalOptions.json ?? false;
|
|
2189
|
-
try {
|
|
2190
|
-
let mcpId = options.mcpId;
|
|
2191
|
-
if (!mcpId) {
|
|
2192
|
-
mcpId = await config.getMcpId();
|
|
2193
|
-
if (!mcpId) {
|
|
2194
|
-
throw new McpError(
|
|
2195
|
-
"No active MCP. Run 'waniwani init' then 'waniwani mcp use <name>'."
|
|
2196
|
-
);
|
|
2197
|
-
}
|
|
2198
|
-
}
|
|
2199
|
-
const token = await auth.getAccessToken();
|
|
2200
|
-
if (!token) {
|
|
2201
|
-
throw new AuthError(
|
|
2202
|
-
"Not logged in. Run 'waniwani login' to authenticate."
|
|
2203
|
-
);
|
|
2204
|
-
}
|
|
2205
|
-
const defaults = await config.getDefaults();
|
|
2206
|
-
const model = options.model ?? defaults.model;
|
|
2207
|
-
const maxSteps = options.maxSteps ? Number.parseInt(options.maxSteps, 10) : defaults.maxSteps;
|
|
2208
|
-
if (!json) {
|
|
2209
|
-
console.log();
|
|
2210
|
-
console.log(chalk14.bold("Task:"), prompt);
|
|
2211
|
-
console.log();
|
|
2212
|
-
}
|
|
2213
|
-
const spinner = ora20("Starting task...").start();
|
|
2214
|
-
const baseUrl = await api.getBaseUrl();
|
|
2215
|
-
const response = await fetch(
|
|
2216
|
-
`${baseUrl}/api/mcp/sandboxes/${mcpId}/task`,
|
|
2217
|
-
{
|
|
2218
|
-
method: "POST",
|
|
2219
|
-
headers: {
|
|
2220
|
-
"Content-Type": "application/json",
|
|
2221
|
-
Authorization: `Bearer ${token}`,
|
|
2222
|
-
Accept: "text/event-stream"
|
|
2223
|
-
},
|
|
2224
|
-
body: JSON.stringify({
|
|
2225
|
-
prompt,
|
|
2226
|
-
model,
|
|
2227
|
-
maxSteps
|
|
2228
|
-
})
|
|
2229
|
-
}
|
|
2230
|
-
);
|
|
2231
|
-
if (!response.ok) {
|
|
2232
|
-
const error = await response.json().catch(() => ({ message: response.statusText }));
|
|
2233
|
-
spinner.fail("Task failed");
|
|
2234
|
-
throw new Error(
|
|
2235
|
-
error.message || `Request failed with status ${response.status}`
|
|
2236
|
-
);
|
|
2237
|
-
}
|
|
2238
|
-
spinner.stop();
|
|
2239
|
-
const steps = [];
|
|
2240
|
-
let stepCount = 0;
|
|
2241
|
-
let maxStepsReached = false;
|
|
2242
|
-
const reader = response.body?.getReader();
|
|
2243
|
-
if (!reader) {
|
|
2244
|
-
throw new Error("No response body");
|
|
2245
|
-
}
|
|
2246
|
-
const decoder = new TextDecoder();
|
|
2247
|
-
let buffer = "";
|
|
2248
|
-
while (true) {
|
|
2249
|
-
const { done, value } = await reader.read();
|
|
2250
|
-
if (done) break;
|
|
2251
|
-
buffer += decoder.decode(value, { stream: true });
|
|
2252
|
-
const lines = buffer.split("\n");
|
|
2253
|
-
buffer = lines.pop() || "";
|
|
2254
|
-
for (const line of lines) {
|
|
2255
|
-
if (line.startsWith("event: ")) {
|
|
2256
|
-
continue;
|
|
2257
|
-
}
|
|
2258
|
-
if (line.startsWith("data: ")) {
|
|
2259
|
-
const data = line.slice(6);
|
|
2260
|
-
if (!data || data === "[DONE]") continue;
|
|
2261
|
-
try {
|
|
2262
|
-
const parsed = JSON.parse(data);
|
|
2263
|
-
if (parsed.type === "text") {
|
|
2264
|
-
const event = parsed;
|
|
2265
|
-
steps.push({ type: "text", text: event.content });
|
|
2266
|
-
if (!json && event.content) {
|
|
2267
|
-
console.log(chalk14.white(event.content));
|
|
2268
|
-
}
|
|
2269
|
-
} else if (parsed.type === "tool_call") {
|
|
2270
|
-
const event = parsed;
|
|
2271
|
-
steps.push({
|
|
2272
|
-
type: "tool_call",
|
|
2273
|
-
tool: event.tool,
|
|
2274
|
-
input: event.input,
|
|
2275
|
-
output: event.output
|
|
2276
|
-
});
|
|
2277
|
-
if (!json) {
|
|
2278
|
-
console.log(chalk14.cyan(`> Using tool: ${event.tool}`));
|
|
2279
|
-
if (event.input?.command) {
|
|
2280
|
-
console.log(chalk14.gray(` $ ${event.input.command}`));
|
|
2281
|
-
}
|
|
2282
|
-
if (event.output) {
|
|
2283
|
-
const outputLines = event.output.split("\n");
|
|
2284
|
-
if (outputLines.length > 10) {
|
|
2285
|
-
console.log(
|
|
2286
|
-
chalk14.gray(outputLines.slice(0, 5).join("\n"))
|
|
2287
|
-
);
|
|
2288
|
-
console.log(
|
|
2289
|
-
chalk14.gray(
|
|
2290
|
-
` ... (${outputLines.length - 10} more lines)`
|
|
2291
|
-
)
|
|
2292
|
-
);
|
|
2293
|
-
console.log(chalk14.gray(outputLines.slice(-5).join("\n")));
|
|
2294
|
-
} else {
|
|
2295
|
-
console.log(chalk14.gray(event.output));
|
|
2296
|
-
}
|
|
2297
|
-
}
|
|
2298
|
-
console.log();
|
|
2299
|
-
}
|
|
2300
|
-
} else if (parsed.success !== void 0) {
|
|
2301
|
-
const doneEvent = parsed;
|
|
2302
|
-
stepCount = doneEvent.stepCount;
|
|
2303
|
-
maxStepsReached = doneEvent.maxStepsReached || false;
|
|
2304
|
-
}
|
|
2305
|
-
} catch {
|
|
2306
|
-
}
|
|
2307
|
-
}
|
|
2308
|
-
}
|
|
2309
|
-
}
|
|
2310
|
-
const result = {
|
|
2311
|
-
success: true,
|
|
2312
|
-
steps,
|
|
2313
|
-
stepCount,
|
|
2314
|
-
maxStepsReached
|
|
2315
|
-
};
|
|
2316
|
-
const finalStepCount = stepCount ?? steps.length;
|
|
2317
|
-
if (json) {
|
|
2318
|
-
formatOutput({ ...result, stepCount: finalStepCount }, true);
|
|
2319
|
-
} else {
|
|
2320
|
-
console.log();
|
|
2321
|
-
console.log(
|
|
2322
|
-
chalk14.green("\u2713"),
|
|
2323
|
-
`Task completed in ${finalStepCount} steps.`
|
|
2324
|
-
);
|
|
2325
|
-
if (maxStepsReached) {
|
|
2326
|
-
console.log(
|
|
2327
|
-
chalk14.yellow("\u26A0"),
|
|
2328
|
-
"Maximum steps reached. Task may be incomplete."
|
|
2329
|
-
);
|
|
2330
|
-
}
|
|
2331
|
-
}
|
|
2332
|
-
} catch (error) {
|
|
2333
|
-
handleError(error, json);
|
|
2334
|
-
process.exit(1);
|
|
2335
|
-
}
|
|
2336
|
-
});
|
|
2337
|
-
|
|
2338
2127
|
// src/cli.ts
|
|
2339
2128
|
var version = "0.1.0";
|
|
2340
2129
|
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");
|
|
@@ -2344,8 +2133,8 @@ program.addCommand(initCommand);
|
|
|
2344
2133
|
program.addCommand(pushCommand);
|
|
2345
2134
|
program.addCommand(devCommand);
|
|
2346
2135
|
program.addCommand(mcpCommand);
|
|
2347
|
-
program.addCommand(taskCommand);
|
|
2348
2136
|
program.addCommand(orgCommand);
|
|
2137
|
+
program.addCommand(configCommand);
|
|
2349
2138
|
|
|
2350
2139
|
// src/index.ts
|
|
2351
2140
|
program.parse(process.argv);
|