@waniwani/cli 0.0.30 → 0.0.33

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 CHANGED
@@ -1,20 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { Command as Command26 } from "commander";
4
+ import { Command as Command25 } from "commander";
5
5
 
6
- // src/commands/dev.ts
7
- import { relative as relative2 } from "path";
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/lib/auth.ts
14
- import { access, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
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 { z as z2 } from "zod";
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 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");
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
- var CONFIG_DIR = join2(homedir2(), ".waniwani");
97
- var AUTH_FILE = join2(CONFIG_DIR, "auth.json");
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 existsSync2 } from "fs";
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 join3, relative } from "path";
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 (existsSync2(join3(current, PROJECT_DIR))) {
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 (existsSync2(join3(current, PROJECT_DIR))) {
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 = join3(projectRoot, PROJECT_DIR, SETTINGS_FILE);
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 = join3(projectRoot, ".gitignore");
438
- if (existsSync2(gitignorePath)) {
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 = join3(dir, entry.name);
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 = join3(targetDir, file.path);
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 = join3(projectRoot, filePath);
599
+ const fullPath = join4(projectRoot, filePath);
497
600
  const relativePath = relative(projectRoot, fullPath);
498
- if (!existsSync2(fullPath)) {
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 Command("dev").description("Watch and sync files to MCP sandbox").option("--no-initial-sync", "Skip initial sync of all files").option(
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(chalk2.yellow("Skipped:"), relativePath);
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(chalk2.green("Synced:"), relativePath);
698
+ console.log(chalk3.green("Synced:"), relativePath);
596
699
  } catch (error) {
597
- console.log(chalk2.red("Failed:"), relativePath);
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(chalk2.bold("Watching for changes..."));
605
- console.log(chalk2.dim("Press Ctrl+C to stop"));
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(chalk2.yellow("Deleted (local only):"), relativePath);
724
+ console.log(chalk3.yellow("Deleted (local only):"), relativePath);
622
725
  });
623
726
  const cleanup = () => {
624
727
  console.log();
625
- console.log(chalk2.dim("Stopping watcher..."));
728
+ console.log(chalk3.dim("Stopping watcher..."));
626
729
  watcher.close().then(() => {
627
730
  process.exit(0);
628
731
  });
@@ -636,97 +739,14 @@ 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 existsSync3 } from "fs";
640
- import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
641
- import { join as join4 } from "path";
642
- import { Command as Command2 } from "commander";
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
- // src/lib/output.ts
646
- import chalk3 from "chalk";
647
- function formatOutput(data, json) {
648
- if (json) {
649
- console.log(JSON.stringify({ success: true, data }, null, 2));
650
- } else {
651
- prettyPrint(data);
652
- }
653
- }
654
- function formatSuccess(message, json) {
655
- if (json) {
656
- console.log(JSON.stringify({ success: true, message }));
657
- } else {
658
- console.log(chalk3.green("\u2713"), message);
659
- }
660
- }
661
- function formatTable(headers, rows, json) {
662
- if (json) {
663
- const data = rows.map(
664
- (row) => Object.fromEntries(headers.map((header, i) => [header, row[i]]))
665
- );
666
- console.log(JSON.stringify({ success: true, data }, null, 2));
667
- } else {
668
- const colWidths = headers.map(
669
- (h, i) => Math.max(h.length, ...rows.map((r) => (r[i] || "").length))
670
- );
671
- const separator = colWidths.map((w) => "-".repeat(w + 2)).join("+");
672
- const formatRow = (row) => row.map((cell, i) => ` ${(cell || "").padEnd(colWidths[i])} `).join("|");
673
- console.log(chalk3.cyan(formatRow(headers)));
674
- console.log(separator);
675
- for (const row of rows) {
676
- console.log(formatRow(row));
677
- }
678
- }
679
- }
680
- function formatList(items, json) {
681
- if (json) {
682
- const data = Object.fromEntries(
683
- items.map((item) => [item.label, item.value])
684
- );
685
- console.log(JSON.stringify({ success: true, data }, null, 2));
686
- } else {
687
- const maxLabelLength = Math.max(...items.map((i) => i.label.length));
688
- items.forEach((item) => {
689
- console.log(
690
- `${chalk3.gray(item.label.padEnd(maxLabelLength))} ${chalk3.white(item.value)}`
691
- );
692
- });
693
- }
694
- }
695
- function prettyPrint(data, indent = 0) {
696
- const prefix = " ".repeat(indent);
697
- if (Array.isArray(data)) {
698
- data.forEach((item, index) => {
699
- console.log(`${prefix}${chalk3.gray(`[${index}]`)}`);
700
- prettyPrint(item, indent + 1);
701
- });
702
- } else if (typeof data === "object" && data !== null) {
703
- for (const [key, value] of Object.entries(data)) {
704
- if (typeof value === "object" && value !== null) {
705
- console.log(`${prefix}${chalk3.gray(key)}:`);
706
- prettyPrint(value, indent + 1);
707
- } else {
708
- console.log(
709
- `${prefix}${chalk3.gray(key)}: ${chalk3.white(String(value))}`
710
- );
711
- }
712
- }
713
- } else {
714
- console.log(`${prefix}${chalk3.white(String(data))}`);
715
- }
716
- }
717
-
718
- // src/commands/init.ts
719
- var PROJECT_CONFIG_DIR = ".waniwani";
720
- var PROJECT_CONFIG_FILE = "settings.json";
721
- var DEFAULT_PROJECT_CONFIG = {
722
- defaults: {
723
- model: "claude-sonnet-4-20250514",
724
- maxSteps: 10
725
- }
726
- };
727
747
  async function loadParentConfig(cwd) {
728
- const parentConfigPath = join4(cwd, PROJECT_CONFIG_DIR, PROJECT_CONFIG_FILE);
729
- if (!existsSync3(parentConfigPath)) {
748
+ const parentConfigPath = join5(cwd, LOCAL_CONFIG_DIR, CONFIG_FILE_NAME);
749
+ if (!existsSync4(parentConfigPath)) {
730
750
  return null;
731
751
  }
732
752
  try {
@@ -738,13 +758,13 @@ async function loadParentConfig(cwd) {
738
758
  return null;
739
759
  }
740
760
  }
741
- 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) => {
742
762
  const globalOptions = command.optsWithGlobals();
743
763
  const json = globalOptions.json ?? false;
744
764
  try {
745
765
  const cwd = process.cwd();
746
- const projectDir = join4(cwd, name);
747
- if (existsSync3(projectDir)) {
766
+ const projectDir = join5(cwd, name);
767
+ if (existsSync4(projectDir)) {
748
768
  if (json) {
749
769
  formatOutput(
750
770
  {
@@ -766,21 +786,12 @@ var initCommand = new Command2("init").description("Create a new MCP project fro
766
786
  await mkdir4(projectDir, { recursive: true });
767
787
  await pullFilesFromSandbox(result.id, projectDir);
768
788
  spinner.text = "Setting up project config...";
769
- const configDir = join4(projectDir, PROJECT_CONFIG_DIR);
770
- const configPath = join4(configDir, PROJECT_CONFIG_FILE);
771
- await mkdir4(configDir, { recursive: true });
772
789
  const parentConfig = await loadParentConfig(cwd);
773
- const projectConfig = {
774
- ...DEFAULT_PROJECT_CONFIG,
790
+ await initConfigAt(projectDir, {
775
791
  ...parentConfig,
776
792
  mcpId: result.id
777
793
  // Always use the new sandbox's mcpId
778
- };
779
- await writeFile4(
780
- configPath,
781
- JSON.stringify(projectConfig, null, " "),
782
- "utf-8"
783
- );
794
+ });
784
795
  spinner.succeed("MCP project created");
785
796
  if (json) {
786
797
  formatOutput(
@@ -817,7 +828,7 @@ var initCommand = new Command2("init").description("Create a new MCP project fro
817
828
  import { spawn } from "child_process";
818
829
  import { createServer } from "http";
819
830
  import chalk4 from "chalk";
820
- import { Command as Command3 } from "commander";
831
+ import { Command as Command5 } from "commander";
821
832
  import ora3 from "ora";
822
833
  var CALLBACK_PORT = 54321;
823
834
  var CALLBACK_URL = `http://localhost:${CALLBACK_PORT}/callback`;
@@ -1093,7 +1104,7 @@ async function exchangeCodeForToken(code, codeVerifier, clientId, resource) {
1093
1104
  }
1094
1105
  return response.json();
1095
1106
  }
1096
- var loginCommand = new Command3("login").description("Log in to WaniWani").option("--no-browser", "Don't open the browser automatically").action(async (options, command) => {
1107
+ var loginCommand = new Command5("login").description("Log in to WaniWani").option("--no-browser", "Don't open the browser automatically").action(async (options, command) => {
1097
1108
  const globalOptions = command.optsWithGlobals();
1098
1109
  const json = globalOptions.json ?? false;
1099
1110
  try {
@@ -1198,8 +1209,8 @@ var loginCommand = new Command3("login").description("Log in to WaniWani").optio
1198
1209
  });
1199
1210
 
1200
1211
  // src/commands/logout.ts
1201
- import { Command as Command4 } from "commander";
1202
- var logoutCommand = new Command4("logout").description("Log out from WaniWani").action(async (_, command) => {
1212
+ import { Command as Command6 } from "commander";
1213
+ var logoutCommand = new Command6("logout").description("Log out from WaniWani").action(async (_, command) => {
1203
1214
  const globalOptions = command.optsWithGlobals();
1204
1215
  const json = globalOptions.json ?? false;
1205
1216
  try {
@@ -1226,46 +1237,10 @@ var logoutCommand = new Command4("logout").description("Log out from WaniWani").
1226
1237
  // src/commands/mcp/index.ts
1227
1238
  import { Command as Command20 } from "commander";
1228
1239
 
1229
- // src/commands/mcp/clear.ts
1230
- import { rm } from "fs/promises";
1231
- import { Command as Command5 } from "commander";
1232
- import ora4 from "ora";
1233
- var clearCommand = new Command5("clear").description("Delete the local MCP project folder").option("--force", "Skip confirmation").action(async (_options, command) => {
1234
- const globalOptions = command.optsWithGlobals();
1235
- const json = globalOptions.json ?? false;
1236
- try {
1237
- const cwd = process.cwd();
1238
- const projectRoot = await findProjectRoot(cwd);
1239
- if (!projectRoot) {
1240
- throw new CLIError(
1241
- "Not in a WaniWani project. No .waniwani directory found.",
1242
- "NOT_IN_PROJECT"
1243
- );
1244
- }
1245
- if (projectRoot === "/" || projectRoot === process.env.HOME) {
1246
- throw new CLIError(
1247
- "Refusing to delete home or root directory.",
1248
- "UNSAFE_DELETE"
1249
- );
1250
- }
1251
- const spinner = ora4(`Deleting ${projectRoot}...`).start();
1252
- await rm(projectRoot, { recursive: true, force: true });
1253
- spinner.succeed("Project folder deleted");
1254
- if (json) {
1255
- formatOutput({ deleted: projectRoot }, true);
1256
- } else {
1257
- formatSuccess(`Deleted: ${projectRoot}`, false);
1258
- }
1259
- } catch (error) {
1260
- handleError(error, json);
1261
- process.exit(1);
1262
- }
1263
- });
1264
-
1265
1240
  // src/commands/mcp/delete.ts
1266
- import { Command as Command6 } from "commander";
1267
- import ora5 from "ora";
1268
- var deleteCommand = new Command6("delete").description("Delete the MCP sandbox").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
1241
+ import { Command as Command7 } from "commander";
1242
+ import ora4 from "ora";
1243
+ var deleteCommand = new Command7("delete").description("Delete the MCP sandbox").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
1269
1244
  const globalOptions = command.optsWithGlobals();
1270
1245
  const json = globalOptions.json ?? false;
1271
1246
  try {
@@ -1276,7 +1251,7 @@ var deleteCommand = new Command6("delete").description("Delete the MCP sandbox")
1276
1251
  throw new McpError("No active MCP. Use --mcp-id to specify one.");
1277
1252
  }
1278
1253
  }
1279
- const spinner = ora5("Deleting MCP sandbox...").start();
1254
+ const spinner = ora4("Deleting MCP sandbox...").start();
1280
1255
  await api.delete(`/api/mcp/sandboxes/${mcpId}`);
1281
1256
  spinner.succeed("MCP sandbox deleted");
1282
1257
  if (await config.getMcpId() === mcpId) {
@@ -1294,9 +1269,9 @@ var deleteCommand = new Command6("delete").description("Delete the MCP sandbox")
1294
1269
  });
1295
1270
 
1296
1271
  // src/commands/mcp/deploy.ts
1297
- import { Command as Command7 } from "commander";
1298
- import ora6 from "ora";
1299
- var deployCommand = new Command7("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) => {
1272
+ import { Command as Command8 } from "commander";
1273
+ import ora5 from "ora";
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) => {
1300
1275
  const globalOptions = command.optsWithGlobals();
1301
1276
  const json = globalOptions.json ?? false;
1302
1277
  try {
@@ -1309,9 +1284,9 @@ var deployCommand = new Command7("deploy").description("Deploy MCP server to Git
1309
1284
  );
1310
1285
  }
1311
1286
  }
1312
- const spinner = ora6("Deploying to GitHub...").start();
1287
+ const spinner = ora5("Deploying to GitHub...").start();
1313
1288
  const result = await api.post(
1314
- `/api/admin/mcps/${mcpId}/deploy`,
1289
+ `/api/mcp/sandboxes/${mcpId}/deploy`,
1315
1290
  {
1316
1291
  repoName: options.repo,
1317
1292
  org: options.org,
@@ -1341,13 +1316,13 @@ var deployCommand = new Command7("deploy").description("Deploy MCP server to Git
1341
1316
  });
1342
1317
 
1343
1318
  // src/commands/mcp/file/index.ts
1344
- import { Command as Command11 } from "commander";
1319
+ import { Command as Command12 } from "commander";
1345
1320
 
1346
1321
  // src/commands/mcp/file/list.ts
1347
1322
  import chalk5 from "chalk";
1348
- import { Command as Command8 } from "commander";
1349
- import ora7 from "ora";
1350
- var listCommand = new Command8("list").description("List files in the MCP sandbox").argument("[path]", "Directory path (defaults to /app)", "/app").option("--mcp-id <id>", "Specific MCP ID").action(async (path, options, command) => {
1323
+ import { Command as Command9 } from "commander";
1324
+ import ora6 from "ora";
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) => {
1351
1326
  const globalOptions = command.optsWithGlobals();
1352
1327
  const json = globalOptions.json ?? false;
1353
1328
  try {
@@ -1360,7 +1335,7 @@ var listCommand = new Command8("list").description("List files in the MCP sandbo
1360
1335
  );
1361
1336
  }
1362
1337
  }
1363
- const spinner = ora7(`Listing ${path}...`).start();
1338
+ const spinner = ora6(`Listing ${path}...`).start();
1364
1339
  const result = await api.get(
1365
1340
  `/api/mcp/sandboxes/${mcpId}/files/list?path=${encodeURIComponent(path)}`
1366
1341
  );
@@ -1396,10 +1371,10 @@ function formatSize(bytes) {
1396
1371
  }
1397
1372
 
1398
1373
  // src/commands/mcp/file/read.ts
1399
- import { writeFile as writeFile5 } from "fs/promises";
1400
- import { Command as Command9 } from "commander";
1401
- import ora8 from "ora";
1402
- var readCommand = new Command9("read").description("Read a file from the MCP sandbox").argument("<path>", "Path in sandbox (e.g., /app/src/index.ts)").option("--mcp-id <id>", "Specific MCP ID").option("--output <file>", "Write to local file instead of stdout").option("--base64", "Output as base64 (for binary files)").action(async (path, options, command) => {
1374
+ import { writeFile as writeFile4 } from "fs/promises";
1375
+ import { Command as Command10 } from "commander";
1376
+ import ora7 from "ora";
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) => {
1403
1378
  const globalOptions = command.optsWithGlobals();
1404
1379
  const json = globalOptions.json ?? false;
1405
1380
  try {
@@ -1413,7 +1388,7 @@ var readCommand = new Command9("read").description("Read a file from the MCP san
1413
1388
  }
1414
1389
  }
1415
1390
  const encoding = options.base64 ? "base64" : "utf8";
1416
- const spinner = ora8(`Reading ${path}...`).start();
1391
+ const spinner = ora7(`Reading ${path}...`).start();
1417
1392
  const result = await api.get(
1418
1393
  `/api/mcp/sandboxes/${mcpId}/files?path=${encodeURIComponent(path)}&encoding=${encoding}`
1419
1394
  );
@@ -1423,7 +1398,7 @@ var readCommand = new Command9("read").description("Read a file from the MCP san
1423
1398
  }
1424
1399
  if (options.output) {
1425
1400
  const buffer = result.encoding === "base64" ? Buffer.from(result.content, "base64") : Buffer.from(result.content, "utf8");
1426
- await writeFile5(options.output, buffer);
1401
+ await writeFile4(options.output, buffer);
1427
1402
  if (json) {
1428
1403
  formatOutput({ path, savedTo: options.output }, true);
1429
1404
  } else {
@@ -1445,9 +1420,9 @@ var readCommand = new Command9("read").description("Read a file from the MCP san
1445
1420
 
1446
1421
  // src/commands/mcp/file/write.ts
1447
1422
  import { readFile as readFile5 } from "fs/promises";
1448
- import { Command as Command10 } from "commander";
1449
- import ora9 from "ora";
1450
- var writeCommand = new Command10("write").description("Write a file to the MCP sandbox").argument("<path>", "Path in sandbox (e.g., /app/src/index.ts)").option("--mcp-id <id>", "Specific MCP ID").option("--content <content>", "Content to write").option("--file <localFile>", "Local file to upload").option("--base64", "Treat content as base64 encoded").action(async (path, options, command) => {
1423
+ import { Command as Command11 } from "commander";
1424
+ import ora8 from "ora";
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) => {
1451
1426
  const globalOptions = command.optsWithGlobals();
1452
1427
  const json = globalOptions.json ?? false;
1453
1428
  try {
@@ -1481,7 +1456,7 @@ var writeCommand = new Command10("write").description("Write a file to the MCP s
1481
1456
  "MISSING_CONTENT"
1482
1457
  );
1483
1458
  }
1484
- const spinner = ora9(`Writing ${path}...`).start();
1459
+ const spinner = ora8(`Writing ${path}...`).start();
1485
1460
  const result = await api.post(
1486
1461
  `/api/mcp/sandboxes/${mcpId}/files`,
1487
1462
  {
@@ -1501,17 +1476,17 @@ var writeCommand = new Command10("write").description("Write a file to the MCP s
1501
1476
  });
1502
1477
 
1503
1478
  // src/commands/mcp/file/index.ts
1504
- var fileCommand = new Command11("file").description("File operations in MCP sandbox").addCommand(readCommand).addCommand(writeCommand).addCommand(listCommand);
1479
+ var fileCommand = new Command12("file").description("File operations in MCP sandbox").addCommand(readCommand).addCommand(writeCommand).addCommand(listCommand);
1505
1480
 
1506
1481
  // src/commands/mcp/list.ts
1507
1482
  import chalk6 from "chalk";
1508
- import { Command as Command12 } from "commander";
1509
- import ora10 from "ora";
1510
- var listCommand2 = new Command12("list").description("List all MCPs in your organization").option("--all", "Include stopped/expired MCPs").action(async (options, command) => {
1483
+ import { Command as Command13 } from "commander";
1484
+ import ora9 from "ora";
1485
+ var listCommand2 = new Command13("list").description("List all MCPs in your organization").option("--all", "Include stopped/expired MCPs").action(async (options, command) => {
1511
1486
  const globalOptions = command.optsWithGlobals();
1512
1487
  const json = globalOptions.json ?? false;
1513
1488
  try {
1514
- const spinner = ora10("Fetching MCPs...").start();
1489
+ const spinner = ora9("Fetching MCPs...").start();
1515
1490
  const mcps = await api.get(
1516
1491
  `/api/mcp/sandboxes${options.all ? "?all=true" : ""}`
1517
1492
  );
@@ -1565,9 +1540,9 @@ var listCommand2 = new Command12("list").description("List all MCPs in your orga
1565
1540
 
1566
1541
  // src/commands/mcp/logs.ts
1567
1542
  import chalk7 from "chalk";
1568
- import { Command as Command13 } from "commander";
1569
- import ora11 from "ora";
1570
- var logsCommand = new Command13("logs").description("Stream logs from the MCP server").argument("[cmdId]", "Command ID (defaults to running server)").option("--mcp-id <id>", "Specific MCP ID").option("-f, --follow", "Keep streaming logs (default)", true).option("--no-follow", "Fetch logs and exit").action(async (cmdIdArg, options, command) => {
1543
+ import { Command as Command14 } from "commander";
1544
+ import ora10 from "ora";
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) => {
1571
1546
  const globalOptions = command.optsWithGlobals();
1572
1547
  const json = globalOptions.json ?? false;
1573
1548
  let reader;
@@ -1598,7 +1573,7 @@ var logsCommand = new Command13("logs").description("Stream logs from the MCP se
1598
1573
  }
1599
1574
  let cmdId = cmdIdArg;
1600
1575
  if (!cmdId) {
1601
- const spinner = ora11("Getting server status...").start();
1576
+ const spinner = ora10("Getting server status...").start();
1602
1577
  const status = await api.post(
1603
1578
  `/api/mcp/sandboxes/${mcpId}/server`,
1604
1579
  { action: "status" }
@@ -1715,9 +1690,9 @@ Error: ${event.error}`));
1715
1690
 
1716
1691
  // src/commands/mcp/run-command.ts
1717
1692
  import chalk8 from "chalk";
1718
- import { Command as Command14 } from "commander";
1719
- import ora12 from "ora";
1720
- var runCommandCommand = new Command14("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(
1693
+ import { Command as Command15 } from "commander";
1694
+ import ora11 from "ora";
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(
1721
1696
  "--timeout <ms>",
1722
1697
  "Command timeout in milliseconds (default: 30000, max: 300000)"
1723
1698
  ).action(async (cmd, args, options, command) => {
@@ -1734,7 +1709,7 @@ var runCommandCommand = new Command14("run-command").description("Run a command
1734
1709
  }
1735
1710
  }
1736
1711
  const timeout = options.timeout ? Number.parseInt(options.timeout, 10) : void 0;
1737
- const spinner = ora12(`Running: ${cmd} ${args.join(" ")}`.trim()).start();
1712
+ const spinner = ora11(`Running: ${cmd} ${args.join(" ")}`.trim()).start();
1738
1713
  const result = await api.post(
1739
1714
  `/api/mcp/sandboxes/${mcpId}/commands`,
1740
1715
  {
@@ -1781,9 +1756,9 @@ var runCommandCommand = new Command14("run-command").description("Run a command
1781
1756
 
1782
1757
  // src/commands/mcp/start.ts
1783
1758
  import chalk9 from "chalk";
1784
- import { Command as Command15 } from "commander";
1785
- import ora13 from "ora";
1786
- var startCommand = new Command15("start").description("Start the MCP server (npm run dev)").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
1759
+ import { Command as Command16 } from "commander";
1760
+ import ora12 from "ora";
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) => {
1787
1762
  const globalOptions = command.optsWithGlobals();
1788
1763
  const json = globalOptions.json ?? false;
1789
1764
  try {
@@ -1796,7 +1771,7 @@ var startCommand = new Command15("start").description("Start the MCP server (npm
1796
1771
  );
1797
1772
  }
1798
1773
  }
1799
- const spinner = ora13("Starting MCP server...").start();
1774
+ const spinner = ora12("Starting MCP server...").start();
1800
1775
  const result = await api.post(
1801
1776
  `/api/mcp/sandboxes/${mcpId}/server`,
1802
1777
  { action: "start" }
@@ -1816,7 +1791,7 @@ var startCommand = new Command15("start").description("Start the MCP server (npm
1816
1791
  console.log();
1817
1792
  console.log(chalk9.bold("Test with MCP Inspector:"));
1818
1793
  console.log(
1819
- ` npx @modelcontextprotocol/inspector --url ${result.previewUrl}`
1794
+ ` npx @modelcontextprotocol/inspector --url ${result.previewUrl}/mcp`
1820
1795
  );
1821
1796
  console.log();
1822
1797
  console.log(
@@ -1831,9 +1806,9 @@ var startCommand = new Command15("start").description("Start the MCP server (npm
1831
1806
 
1832
1807
  // src/commands/mcp/status.ts
1833
1808
  import chalk10 from "chalk";
1834
- import { Command as Command16 } from "commander";
1835
- import ora14 from "ora";
1836
- var statusCommand = new Command16("status").description("Show current MCP sandbox status").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
1809
+ import { Command as Command17 } from "commander";
1810
+ import ora13 from "ora";
1811
+ var statusCommand = new Command17("status").description("Show current MCP sandbox status").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
1837
1812
  const globalOptions = command.optsWithGlobals();
1838
1813
  const json = globalOptions.json ?? false;
1839
1814
  try {
@@ -1846,7 +1821,7 @@ var statusCommand = new Command16("status").description("Show current MCP sandbo
1846
1821
  );
1847
1822
  }
1848
1823
  }
1849
- const spinner = ora14("Fetching MCP status...").start();
1824
+ const spinner = ora13("Fetching MCP status...").start();
1850
1825
  const [result, serverStatus] = await Promise.all([
1851
1826
  api.get(`/api/mcp/sandboxes/${mcpId}`),
1852
1827
  api.post(`/api/mcp/sandboxes/${mcpId}/server`, {
@@ -1889,9 +1864,9 @@ var statusCommand = new Command16("status").description("Show current MCP sandbo
1889
1864
  });
1890
1865
 
1891
1866
  // src/commands/mcp/stop.ts
1892
- import { Command as Command17 } from "commander";
1893
- import ora15 from "ora";
1894
- var stopCommand = new Command17("stop").description("Stop the MCP server process").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
1867
+ import { Command as Command18 } from "commander";
1868
+ import ora14 from "ora";
1869
+ var stopCommand = new Command18("stop").description("Stop the MCP server process").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
1895
1870
  const globalOptions = command.optsWithGlobals();
1896
1871
  const json = globalOptions.json ?? false;
1897
1872
  try {
@@ -1904,7 +1879,7 @@ var stopCommand = new Command17("stop").description("Stop the MCP server process
1904
1879
  );
1905
1880
  }
1906
1881
  }
1907
- const spinner = ora15("Stopping MCP server...").start();
1882
+ const spinner = ora14("Stopping MCP server...").start();
1908
1883
  const result = await api.post(
1909
1884
  `/api/mcp/sandboxes/${mcpId}/server`,
1910
1885
  { action: "stop" }
@@ -1925,106 +1900,15 @@ var stopCommand = new Command17("stop").description("Stop the MCP server process
1925
1900
  }
1926
1901
  });
1927
1902
 
1928
- // src/commands/mcp/test.ts
1929
- import chalk11 from "chalk";
1930
- import { Command as Command18 } from "commander";
1931
- import ora16 from "ora";
1932
- var testCommand = new Command18("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(
1933
- async (tool, args, options, command) => {
1934
- const globalOptions = command.optsWithGlobals();
1935
- const json = globalOptions.json ?? false;
1936
- try {
1937
- let mcpId = options.mcpId;
1938
- if (!mcpId) {
1939
- mcpId = await config.getMcpId();
1940
- if (!mcpId) {
1941
- throw new McpError(
1942
- "No active MCP. Run 'waniwani mcp create <name>' or 'waniwani mcp use <name>'."
1943
- );
1944
- }
1945
- }
1946
- if (!tool) {
1947
- const spinner = ora16("Fetching available tools...").start();
1948
- const result = await api.post(
1949
- `/api/mcp/sandboxes/${mcpId}/test`,
1950
- { action: "list" }
1951
- );
1952
- spinner.stop();
1953
- const tools = result.tools;
1954
- if (json) {
1955
- formatOutput({ tools }, true);
1956
- } else {
1957
- if (tools.length === 0) {
1958
- console.log("No tools available.");
1959
- } else {
1960
- console.log(chalk11.bold("\nAvailable Tools:\n"));
1961
- formatTable(
1962
- ["Name", "Description"],
1963
- tools.map((t) => [t.name, t.description || "No description"]),
1964
- false
1965
- );
1966
- console.log(
1967
- `
1968
- Test a tool: waniwani mcp test <tool-name> '{"arg": "value"}'`
1969
- );
1970
- }
1971
- }
1972
- } else {
1973
- let toolArgs = {};
1974
- if (args.length > 0) {
1975
- try {
1976
- toolArgs = JSON.parse(args.join(" "));
1977
- } catch {
1978
- throw new SandboxError(
1979
- `Invalid JSON arguments. Expected format: '{"key": "value"}'`
1980
- );
1981
- }
1982
- }
1983
- const spinner = ora16(`Calling tool "${tool}"...`).start();
1984
- const startTime = Date.now();
1985
- const result = await api.post(
1986
- `/api/mcp/sandboxes/${mcpId}/test`,
1987
- {
1988
- action: "call",
1989
- tool,
1990
- args: toolArgs
1991
- }
1992
- );
1993
- const duration = result.duration || Date.now() - startTime;
1994
- spinner.stop();
1995
- const output = {
1996
- tool,
1997
- input: toolArgs,
1998
- result: result.result,
1999
- duration
2000
- };
2001
- if (json) {
2002
- formatOutput(output, true);
2003
- } else {
2004
- console.log(chalk11.bold("\nTool Result:\n"));
2005
- console.log(chalk11.gray("Tool:"), tool);
2006
- console.log(chalk11.gray("Input:"), JSON.stringify(toolArgs));
2007
- console.log(chalk11.gray("Duration:"), `${duration}ms`);
2008
- console.log(chalk11.gray("Result:"));
2009
- console.log(JSON.stringify(result.result, null, 2));
2010
- }
2011
- }
2012
- } catch (error) {
2013
- handleError(error, json);
2014
- process.exit(1);
2015
- }
2016
- }
2017
- );
2018
-
2019
1903
  // src/commands/mcp/use.ts
2020
1904
  import { Command as Command19 } from "commander";
2021
- import ora17 from "ora";
1905
+ import ora15 from "ora";
2022
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) => {
2023
1907
  const globalOptions = command.optsWithGlobals();
2024
1908
  const json = globalOptions.json ?? false;
2025
1909
  try {
2026
- const spinner = ora17("Fetching MCPs...").start();
2027
- const mcps = await api.get("/api/admin/mcps");
1910
+ const spinner = ora15("Fetching MCPs...").start();
1911
+ const mcps = await api.get("/api/mcp/sandboxes");
2028
1912
  spinner.stop();
2029
1913
  const mcp = mcps.find((m) => m.name === name);
2030
1914
  if (!mcp) {
@@ -2059,20 +1943,20 @@ var useCommand = new Command19("use").description("Select an MCP to use for subs
2059
1943
  });
2060
1944
 
2061
1945
  // src/commands/mcp/index.ts
2062
- 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(clearCommand).addCommand(testCommand).addCommand(deployCommand).addCommand(fileCommand).addCommand(runCommandCommand);
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);
2063
1947
 
2064
1948
  // src/commands/org/index.ts
2065
1949
  import { Command as Command23 } from "commander";
2066
1950
 
2067
1951
  // src/commands/org/list.ts
2068
- import chalk12 from "chalk";
1952
+ import chalk11 from "chalk";
2069
1953
  import { Command as Command21 } from "commander";
2070
- import ora18 from "ora";
1954
+ import ora16 from "ora";
2071
1955
  var listCommand3 = new Command21("list").description("List your organizations").action(async (_, command) => {
2072
1956
  const globalOptions = command.optsWithGlobals();
2073
1957
  const json = globalOptions.json ?? false;
2074
1958
  try {
2075
- const spinner = ora18("Fetching organizations...").start();
1959
+ const spinner = ora16("Fetching organizations...").start();
2076
1960
  const result = await api.get("/api/oauth/orgs");
2077
1961
  spinner.stop();
2078
1962
  const { orgs, activeOrgId } = result;
@@ -2092,11 +1976,11 @@ var listCommand3 = new Command21("list").description("List your organizations").
2092
1976
  console.log("No organizations found.");
2093
1977
  return;
2094
1978
  }
2095
- console.log(chalk12.bold("\nOrganizations:\n"));
1979
+ console.log(chalk11.bold("\nOrganizations:\n"));
2096
1980
  const rows = orgs.map((o) => {
2097
1981
  const isActive = o.id === activeOrgId;
2098
1982
  return [
2099
- isActive ? chalk12.cyan(`* ${o.name}`) : ` ${o.name}`,
1983
+ isActive ? chalk11.cyan(`* ${o.name}`) : ` ${o.name}`,
2100
1984
  o.slug,
2101
1985
  o.role
2102
1986
  ];
@@ -2106,7 +1990,7 @@ var listCommand3 = new Command21("list").description("List your organizations").
2106
1990
  if (activeOrgId) {
2107
1991
  const activeOrg = orgs.find((o) => o.id === activeOrgId);
2108
1992
  if (activeOrg) {
2109
- console.log(`Active organization: ${chalk12.cyan(activeOrg.name)}`);
1993
+ console.log(`Active organization: ${chalk11.cyan(activeOrg.name)}`);
2110
1994
  }
2111
1995
  }
2112
1996
  console.log("\nSwitch organization: waniwani org switch <name>");
@@ -2119,12 +2003,12 @@ var listCommand3 = new Command21("list").description("List your organizations").
2119
2003
 
2120
2004
  // src/commands/org/switch.ts
2121
2005
  import { Command as Command22 } from "commander";
2122
- import ora19 from "ora";
2006
+ import ora17 from "ora";
2123
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) => {
2124
2008
  const globalOptions = command.optsWithGlobals();
2125
2009
  const json = globalOptions.json ?? false;
2126
2010
  try {
2127
- const spinner = ora19("Fetching organizations...").start();
2011
+ const spinner = ora17("Fetching organizations...").start();
2128
2012
  const { orgs } = await api.get("/api/oauth/orgs");
2129
2013
  const org = orgs.find((o) => o.name === name || o.slug === name);
2130
2014
  if (!org) {
@@ -2160,9 +2044,9 @@ var switchCommand = new Command22("switch").description("Switch to a different o
2160
2044
  var orgCommand = new Command23("org").description("Organization management commands").addCommand(listCommand3).addCommand(switchCommand);
2161
2045
 
2162
2046
  // src/commands/push.ts
2163
- import chalk13 from "chalk";
2047
+ import chalk12 from "chalk";
2164
2048
  import { Command as Command24 } from "commander";
2165
- import ora20 from "ora";
2049
+ import ora18 from "ora";
2166
2050
  var BATCH_SIZE2 = 50;
2167
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) => {
2168
2052
  const globalOptions = command.optsWithGlobals();
@@ -2183,7 +2067,7 @@ var pushCommand = new Command24("push").description("Sync local files to MCP san
2183
2067
  "NO_MCP_ID"
2184
2068
  );
2185
2069
  }
2186
- const spinner = ora20("Collecting files...").start();
2070
+ const spinner = ora18("Collecting files...").start();
2187
2071
  const files = await collectFiles(projectRoot);
2188
2072
  if (files.length === 0) {
2189
2073
  spinner.info("No files to sync");
@@ -2196,7 +2080,7 @@ var pushCommand = new Command24("push").description("Sync local files to MCP san
2196
2080
  if (options.dryRun) {
2197
2081
  spinner.stop();
2198
2082
  console.log();
2199
- console.log(chalk13.bold("Files that would be synced:"));
2083
+ console.log(chalk12.bold("Files that would be synced:"));
2200
2084
  for (const file of files) {
2201
2085
  console.log(` ${file.path}`);
2202
2086
  }
@@ -2240,173 +2124,17 @@ var pushCommand = new Command24("push").description("Sync local files to MCP san
2240
2124
  }
2241
2125
  });
2242
2126
 
2243
- // src/commands/task.ts
2244
- import chalk14 from "chalk";
2245
- import { Command as Command25 } from "commander";
2246
- import ora21 from "ora";
2247
- var taskCommand = new Command25("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) => {
2248
- const globalOptions = command.optsWithGlobals();
2249
- const json = globalOptions.json ?? false;
2250
- try {
2251
- let mcpId = options.mcpId;
2252
- if (!mcpId) {
2253
- mcpId = await config.getMcpId();
2254
- if (!mcpId) {
2255
- throw new McpError(
2256
- "No active MCP. Run 'waniwani init' then 'waniwani mcp use <name>'."
2257
- );
2258
- }
2259
- }
2260
- const token = await auth.getAccessToken();
2261
- if (!token) {
2262
- throw new AuthError(
2263
- "Not logged in. Run 'waniwani login' to authenticate."
2264
- );
2265
- }
2266
- const defaults = await config.getDefaults();
2267
- const model = options.model ?? defaults.model;
2268
- const maxSteps = options.maxSteps ? Number.parseInt(options.maxSteps, 10) : defaults.maxSteps;
2269
- if (!json) {
2270
- console.log();
2271
- console.log(chalk14.bold("Task:"), prompt);
2272
- console.log();
2273
- }
2274
- const spinner = ora21("Starting task...").start();
2275
- const baseUrl = await api.getBaseUrl();
2276
- const response = await fetch(
2277
- `${baseUrl}/api/mcp/sandboxes/${mcpId}/task`,
2278
- {
2279
- method: "POST",
2280
- headers: {
2281
- "Content-Type": "application/json",
2282
- Authorization: `Bearer ${token}`,
2283
- Accept: "text/event-stream"
2284
- },
2285
- body: JSON.stringify({
2286
- prompt,
2287
- model,
2288
- maxSteps
2289
- })
2290
- }
2291
- );
2292
- if (!response.ok) {
2293
- const error = await response.json().catch(() => ({ message: response.statusText }));
2294
- spinner.fail("Task failed");
2295
- throw new Error(
2296
- error.message || `Request failed with status ${response.status}`
2297
- );
2298
- }
2299
- spinner.stop();
2300
- const steps = [];
2301
- let stepCount = 0;
2302
- let maxStepsReached = false;
2303
- const reader = response.body?.getReader();
2304
- if (!reader) {
2305
- throw new Error("No response body");
2306
- }
2307
- const decoder = new TextDecoder();
2308
- let buffer = "";
2309
- while (true) {
2310
- const { done, value } = await reader.read();
2311
- if (done) break;
2312
- buffer += decoder.decode(value, { stream: true });
2313
- const lines = buffer.split("\n");
2314
- buffer = lines.pop() || "";
2315
- for (const line of lines) {
2316
- if (line.startsWith("event: ")) {
2317
- continue;
2318
- }
2319
- if (line.startsWith("data: ")) {
2320
- const data = line.slice(6);
2321
- if (!data || data === "[DONE]") continue;
2322
- try {
2323
- const parsed = JSON.parse(data);
2324
- if (parsed.type === "text") {
2325
- const event = parsed;
2326
- steps.push({ type: "text", text: event.content });
2327
- if (!json && event.content) {
2328
- console.log(chalk14.white(event.content));
2329
- }
2330
- } else if (parsed.type === "tool_call") {
2331
- const event = parsed;
2332
- steps.push({
2333
- type: "tool_call",
2334
- tool: event.tool,
2335
- input: event.input,
2336
- output: event.output
2337
- });
2338
- if (!json) {
2339
- console.log(chalk14.cyan(`> Using tool: ${event.tool}`));
2340
- if (event.input?.command) {
2341
- console.log(chalk14.gray(` $ ${event.input.command}`));
2342
- }
2343
- if (event.output) {
2344
- const outputLines = event.output.split("\n");
2345
- if (outputLines.length > 10) {
2346
- console.log(
2347
- chalk14.gray(outputLines.slice(0, 5).join("\n"))
2348
- );
2349
- console.log(
2350
- chalk14.gray(
2351
- ` ... (${outputLines.length - 10} more lines)`
2352
- )
2353
- );
2354
- console.log(chalk14.gray(outputLines.slice(-5).join("\n")));
2355
- } else {
2356
- console.log(chalk14.gray(event.output));
2357
- }
2358
- }
2359
- console.log();
2360
- }
2361
- } else if (parsed.success !== void 0) {
2362
- const doneEvent = parsed;
2363
- stepCount = doneEvent.stepCount;
2364
- maxStepsReached = doneEvent.maxStepsReached || false;
2365
- }
2366
- } catch {
2367
- }
2368
- }
2369
- }
2370
- }
2371
- const result = {
2372
- success: true,
2373
- steps,
2374
- stepCount,
2375
- maxStepsReached
2376
- };
2377
- const finalStepCount = stepCount ?? steps.length;
2378
- if (json) {
2379
- formatOutput({ ...result, stepCount: finalStepCount }, true);
2380
- } else {
2381
- console.log();
2382
- console.log(
2383
- chalk14.green("\u2713"),
2384
- `Task completed in ${finalStepCount} steps.`
2385
- );
2386
- if (maxStepsReached) {
2387
- console.log(
2388
- chalk14.yellow("\u26A0"),
2389
- "Maximum steps reached. Task may be incomplete."
2390
- );
2391
- }
2392
- }
2393
- } catch (error) {
2394
- handleError(error, json);
2395
- process.exit(1);
2396
- }
2397
- });
2398
-
2399
2127
  // src/cli.ts
2400
2128
  var version = "0.1.0";
2401
- var program = new Command26().name("waniwani").description("WaniWani CLI for MCP development workflow").version(version).option("--json", "Output results as JSON").option("--verbose", "Enable verbose logging");
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");
2402
2130
  program.addCommand(loginCommand);
2403
2131
  program.addCommand(logoutCommand);
2404
2132
  program.addCommand(initCommand);
2405
2133
  program.addCommand(pushCommand);
2406
2134
  program.addCommand(devCommand);
2407
2135
  program.addCommand(mcpCommand);
2408
- program.addCommand(taskCommand);
2409
2136
  program.addCommand(orgCommand);
2137
+ program.addCommand(configCommand);
2410
2138
 
2411
2139
  // src/index.ts
2412
2140
  program.parse(process.argv);