@waniwani/cli 0.0.26 → 0.0.28

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