@waniwani/cli 0.0.6 → 0.0.12

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,117 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { Command as Command15 } from "commander";
5
-
6
- // src/commands/login.ts
7
- import { spawn } from "child_process";
8
- import { createServer } from "http";
9
- import chalk3 from "chalk";
10
- import { Command } from "commander";
11
- import ora from "ora";
4
+ import { Command as Command16 } from "commander";
12
5
 
13
- // src/lib/auth.ts
14
- import { access, mkdir, readFile, writeFile } from "fs/promises";
15
- import { homedir } from "os";
6
+ // src/commands/init.ts
7
+ import { existsSync } from "fs";
8
+ import { mkdir, writeFile } from "fs/promises";
16
9
  import { join } from "path";
17
- import { z } from "zod";
18
- var CONFIG_DIR = join(homedir(), ".waniwani");
19
- var AUTH_FILE = join(CONFIG_DIR, "auth.json");
20
- var AuthStoreSchema = z.object({
21
- accessToken: z.string().nullable().default(null),
22
- refreshToken: z.string().nullable().default(null),
23
- expiresAt: z.string().nullable().default(null)
24
- });
25
- var API_BASE_URL = process.env.WANIWANI_API_URL || "https://waniwani.com";
26
- async function ensureConfigDir() {
27
- await mkdir(CONFIG_DIR, { recursive: true });
28
- }
29
- async function readAuthStore() {
30
- await ensureConfigDir();
31
- try {
32
- await access(AUTH_FILE);
33
- const content = await readFile(AUTH_FILE, "utf-8");
34
- return AuthStoreSchema.parse(JSON.parse(content));
35
- } catch {
36
- return AuthStoreSchema.parse({});
37
- }
38
- }
39
- async function writeAuthStore(store) {
40
- await ensureConfigDir();
41
- await writeFile(AUTH_FILE, JSON.stringify(store, null, 2), "utf-8");
42
- }
43
- var AuthManager = class {
44
- storeCache = null;
45
- async getStore() {
46
- if (!this.storeCache) {
47
- this.storeCache = await readAuthStore();
48
- }
49
- return this.storeCache;
50
- }
51
- async saveStore(store) {
52
- this.storeCache = store;
53
- await writeAuthStore(store);
54
- }
55
- async isLoggedIn() {
56
- const store = await this.getStore();
57
- return !!store.accessToken;
58
- }
59
- async getAccessToken() {
60
- const store = await this.getStore();
61
- return store.accessToken;
62
- }
63
- async getRefreshToken() {
64
- const store = await this.getStore();
65
- return store.refreshToken;
66
- }
67
- async setTokens(accessToken, refreshToken, expiresIn) {
68
- const expiresAt = new Date(Date.now() + expiresIn * 1e3).toISOString();
69
- const store = await this.getStore();
70
- store.accessToken = accessToken;
71
- store.refreshToken = refreshToken;
72
- store.expiresAt = expiresAt;
73
- await this.saveStore(store);
74
- }
75
- async clear() {
76
- const emptyStore = AuthStoreSchema.parse({});
77
- await this.saveStore(emptyStore);
78
- }
79
- async isTokenExpired() {
80
- const store = await this.getStore();
81
- if (!store.expiresAt) return true;
82
- return new Date(store.expiresAt).getTime() - 5 * 60 * 1e3 < Date.now();
83
- }
84
- async tryRefreshToken() {
85
- const refreshToken = await this.getRefreshToken();
86
- if (!refreshToken) return false;
87
- try {
88
- const response = await fetch(`${API_BASE_URL}/api/auth/oauth2/token`, {
89
- method: "POST",
90
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
91
- body: new URLSearchParams({
92
- grant_type: "refresh_token",
93
- refresh_token: refreshToken,
94
- client_id: "waniwani-cli"
95
- }).toString()
96
- });
97
- if (!response.ok) {
98
- await this.clear();
99
- return false;
100
- }
101
- const data = await response.json();
102
- await this.setTokens(
103
- data.access_token,
104
- data.refresh_token,
105
- data.expires_in
106
- );
107
- return true;
108
- } catch {
109
- await this.clear();
110
- return false;
111
- }
112
- }
113
- };
114
- var auth = new AuthManager();
10
+ import { Command } from "commander";
115
11
 
116
12
  // src/lib/errors.ts
117
13
  import chalk from "chalk";
@@ -237,8 +133,297 @@ function prettyPrint(data, indent = 0) {
237
133
  }
238
134
  }
239
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";
189
+ import ora from "ora";
190
+
191
+ // src/lib/auth.ts
192
+ import { access, mkdir as mkdir4, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
193
+ import { homedir as homedir2 } from "os";
194
+ import { join as join4 } from "path";
195
+ import { z as z3 } from "zod";
196
+
197
+ // src/lib/config.ts
198
+ import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
199
+ import { homedir } from "os";
200
+ import { join as join3 } from "path";
201
+ import { z as z2 } from "zod";
202
+
203
+ // src/lib/project-config.ts
204
+ import { existsSync as existsSync2 } from "fs";
205
+ import { mkdir as mkdir2, readFile, writeFile as writeFile2 } from "fs/promises";
206
+ import { join as join2 } from "path";
207
+ import { z } from "zod";
208
+ var PROJECT_CONFIG_DIR2 = ".waniwani";
209
+ var PROJECT_CONFIG_FILE2 = "settings.local.json";
210
+ var ProjectConfigSchema = z.object({
211
+ mcpId: z.string().optional(),
212
+ defaults: z.object({
213
+ model: z.string().optional(),
214
+ maxSteps: z.number().optional()
215
+ }).optional()
216
+ });
217
+ var projectConfigCache;
218
+ function getProjectConfigPath() {
219
+ return join2(process.cwd(), PROJECT_CONFIG_DIR2, PROJECT_CONFIG_FILE2);
220
+ }
221
+ function getProjectConfigDir() {
222
+ return join2(process.cwd(), PROJECT_CONFIG_DIR2);
223
+ }
224
+ function hasProjectConfig() {
225
+ return existsSync2(getProjectConfigDir());
226
+ }
227
+ async function loadProjectConfig() {
228
+ if (projectConfigCache !== void 0) {
229
+ return projectConfigCache;
230
+ }
231
+ const configPath = getProjectConfigPath();
232
+ try {
233
+ const content = await readFile(configPath, "utf-8");
234
+ projectConfigCache = ProjectConfigSchema.parse(JSON.parse(content));
235
+ return projectConfigCache;
236
+ } catch {
237
+ projectConfigCache = null;
238
+ return null;
239
+ }
240
+ }
241
+ async function saveProjectConfig(config2) {
242
+ const configDir = getProjectConfigDir();
243
+ const configPath = getProjectConfigPath();
244
+ await mkdir2(configDir, { recursive: true });
245
+ const existing = await loadProjectConfig() ?? {};
246
+ const merged = ProjectConfigSchema.parse({ ...existing, ...config2 });
247
+ await writeFile2(configPath, JSON.stringify(merged, null, " "), "utf-8");
248
+ projectConfigCache = merged;
249
+ }
250
+
251
+ // src/lib/config.ts
252
+ var CONFIG_DIR = join3(homedir(), ".waniwani");
253
+ var CONFIG_FILE = join3(CONFIG_DIR, "config.json");
254
+ var DEFAULT_API_URL = "https://app.waniwani.ai";
255
+ var ConfigSchema = z2.object({
256
+ defaults: z2.object({ model: z2.string(), maxSteps: z2.number() }).default({ model: "claude-sonnet-4-20250514", maxSteps: 10 }),
257
+ activeMcpId: z2.string().nullable().default(null),
258
+ apiUrl: z2.string().nullable().default(null)
259
+ });
260
+ var cache = null;
261
+ async function load() {
262
+ if (cache) return cache;
263
+ try {
264
+ cache = ConfigSchema.parse(
265
+ JSON.parse(await readFile2(CONFIG_FILE, "utf-8"))
266
+ );
267
+ } catch {
268
+ cache = ConfigSchema.parse({});
269
+ }
270
+ return cache;
271
+ }
272
+ async function save(cfg) {
273
+ cache = cfg;
274
+ await mkdir3(CONFIG_DIR, { recursive: true });
275
+ await writeFile3(CONFIG_FILE, JSON.stringify(cfg, null, 2));
276
+ }
277
+ async function update(fn) {
278
+ const cfg = await load();
279
+ fn(cfg);
280
+ await save(cfg);
281
+ }
282
+ var config = {
283
+ getDefaults: async () => {
284
+ const cfg = await load();
285
+ return cfg.defaults;
286
+ },
287
+ getEffectiveDefaults: async () => {
288
+ const global = await load();
289
+ const project = await loadProjectConfig();
290
+ return { ...global.defaults, ...project?.defaults };
291
+ },
292
+ setDefaults: (defaults) => {
293
+ return update((cfg) => {
294
+ cfg.defaults = { ...cfg.defaults, ...defaults };
295
+ });
296
+ },
297
+ getActiveMcpId: async () => {
298
+ const cfg = await load();
299
+ return cfg.activeMcpId;
300
+ },
301
+ getEffectiveMcpId: async () => {
302
+ const project = await loadProjectConfig();
303
+ if (project?.mcpId) return project.mcpId;
304
+ const cfg = await load();
305
+ return cfg.activeMcpId;
306
+ },
307
+ setActiveMcpId: (id) => {
308
+ return update((cfg) => {
309
+ cfg.activeMcpId = id;
310
+ });
311
+ },
312
+ getApiUrl: async () => {
313
+ if (process.env.WANIWANI_API_URL) return process.env.WANIWANI_API_URL;
314
+ const cfg = await load();
315
+ return cfg.apiUrl || DEFAULT_API_URL;
316
+ },
317
+ setApiUrl: (url) => {
318
+ return update((cfg) => {
319
+ cfg.apiUrl = url;
320
+ });
321
+ },
322
+ clear: () => {
323
+ return save(ConfigSchema.parse({}));
324
+ }
325
+ };
326
+
327
+ // src/lib/auth.ts
328
+ var CONFIG_DIR2 = join4(homedir2(), ".waniwani");
329
+ var AUTH_FILE = join4(CONFIG_DIR2, "auth.json");
330
+ var AuthStoreSchema = z3.object({
331
+ accessToken: z3.string().nullable().default(null),
332
+ refreshToken: z3.string().nullable().default(null),
333
+ expiresAt: z3.string().nullable().default(null)
334
+ });
335
+ async function ensureConfigDir() {
336
+ await mkdir4(CONFIG_DIR2, { recursive: true });
337
+ }
338
+ async function readAuthStore() {
339
+ await ensureConfigDir();
340
+ try {
341
+ await access(AUTH_FILE);
342
+ const content = await readFile3(AUTH_FILE, "utf-8");
343
+ return AuthStoreSchema.parse(JSON.parse(content));
344
+ } catch {
345
+ return AuthStoreSchema.parse({});
346
+ }
347
+ }
348
+ async function writeAuthStore(store) {
349
+ await ensureConfigDir();
350
+ await writeFile4(AUTH_FILE, JSON.stringify(store, null, 2), "utf-8");
351
+ }
352
+ var AuthManager = class {
353
+ storeCache = null;
354
+ async getStore() {
355
+ if (!this.storeCache) {
356
+ this.storeCache = await readAuthStore();
357
+ }
358
+ return this.storeCache;
359
+ }
360
+ async saveStore(store) {
361
+ this.storeCache = store;
362
+ await writeAuthStore(store);
363
+ }
364
+ async isLoggedIn() {
365
+ const store = await this.getStore();
366
+ return !!store.accessToken;
367
+ }
368
+ async getAccessToken() {
369
+ const store = await this.getStore();
370
+ return store.accessToken;
371
+ }
372
+ async getRefreshToken() {
373
+ const store = await this.getStore();
374
+ return store.refreshToken;
375
+ }
376
+ async setTokens(accessToken, refreshToken, expiresIn) {
377
+ const expiresAt = new Date(Date.now() + expiresIn * 1e3).toISOString();
378
+ const store = await this.getStore();
379
+ store.accessToken = accessToken;
380
+ store.refreshToken = refreshToken;
381
+ store.expiresAt = expiresAt;
382
+ await this.saveStore(store);
383
+ }
384
+ async clear() {
385
+ const emptyStore = AuthStoreSchema.parse({});
386
+ await this.saveStore(emptyStore);
387
+ }
388
+ async isTokenExpired() {
389
+ const store = await this.getStore();
390
+ if (!store.expiresAt) return true;
391
+ return new Date(store.expiresAt).getTime() - 5 * 60 * 1e3 < Date.now();
392
+ }
393
+ async tryRefreshToken() {
394
+ const refreshToken = await this.getRefreshToken();
395
+ if (!refreshToken) return false;
396
+ try {
397
+ const apiUrl = await config.getApiUrl();
398
+ const response = await fetch(`${apiUrl}/api/auth/oauth2/token`, {
399
+ method: "POST",
400
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
401
+ body: new URLSearchParams({
402
+ grant_type: "refresh_token",
403
+ refresh_token: refreshToken,
404
+ client_id: "waniwani-cli"
405
+ }).toString()
406
+ });
407
+ if (!response.ok) {
408
+ await this.clear();
409
+ return false;
410
+ }
411
+ const data = await response.json();
412
+ await this.setTokens(
413
+ data.access_token,
414
+ data.refresh_token,
415
+ data.expires_in
416
+ );
417
+ return true;
418
+ } catch {
419
+ await this.clear();
420
+ return false;
421
+ }
422
+ }
423
+ };
424
+ var auth = new AuthManager();
425
+
240
426
  // src/commands/login.ts
241
- var API_BASE_URL2 = process.env.WANIWANI_API_URL || "https://waniwani.com";
242
427
  var CALLBACK_PORT = 54321;
243
428
  var CALLBACK_URL = `http://localhost:${CALLBACK_PORT}/callback`;
244
429
  var CLIENT_ID = "waniwani-cli";
@@ -362,7 +547,8 @@ async function waitForCallback(expectedState, timeoutMs = 3e5) {
362
547
  });
363
548
  }
364
549
  async function exchangeCodeForToken(code, codeVerifier) {
365
- const response = await fetch(`${API_BASE_URL2}/api/auth/oauth2/token`, {
550
+ const apiUrl = await config.getApiUrl();
551
+ const response = await fetch(`${apiUrl}/api/auth/oauth2/token`, {
366
552
  method: "POST",
367
553
  headers: {
368
554
  "Content-Type": "application/x-www-form-urlencoded"
@@ -384,7 +570,7 @@ async function exchangeCodeForToken(code, codeVerifier) {
384
570
  }
385
571
  return response.json();
386
572
  }
387
- var loginCommand = new Command("login").description("Log in to WaniWani").option("--no-browser", "Don't open the browser automatically").action(async (options, command) => {
573
+ var loginCommand = new Command2("login").description("Log in to WaniWani").option("--no-browser", "Don't open the browser automatically").action(async (options, command) => {
388
574
  const globalOptions = command.optsWithGlobals();
389
575
  const json = globalOptions.json ?? false;
390
576
  try {
@@ -406,7 +592,8 @@ var loginCommand = new Command("login").description("Log in to WaniWani").option
406
592
  const codeVerifier = generateCodeVerifier();
407
593
  const codeChallenge = await generateCodeChallenge(codeVerifier);
408
594
  const state = generateState();
409
- const authUrl = new URL(`${API_BASE_URL2}/oauth/authorize`);
595
+ const apiUrl = await config.getApiUrl();
596
+ const authUrl = new URL(`${apiUrl}/oauth/authorize`);
410
597
  authUrl.searchParams.set("client_id", CLIENT_ID);
411
598
  authUrl.searchParams.set("redirect_uri", CALLBACK_URL);
412
599
  authUrl.searchParams.set("response_type", "code");
@@ -456,78 +643,8 @@ var loginCommand = new Command("login").description("Log in to WaniWani").option
456
643
  });
457
644
 
458
645
  // src/commands/logout.ts
459
- import { Command as Command2 } from "commander";
460
-
461
- // src/lib/config.ts
462
- import { access as access2, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
463
- import { homedir as homedir2 } from "os";
464
- import { join as join2 } from "path";
465
- import { z as z2 } from "zod";
466
- var CONFIG_DIR2 = join2(homedir2(), ".waniwani");
467
- var CONFIG_FILE = join2(CONFIG_DIR2, "config.json");
468
- var ConfigSchema = z2.object({
469
- defaults: z2.object({
470
- model: z2.string().default("claude-sonnet-4-20250514"),
471
- maxSteps: z2.number().default(10)
472
- }).default(() => ({ model: "claude-sonnet-4-20250514", maxSteps: 10 })),
473
- activeMcpId: z2.string().nullable().default(null)
474
- });
475
- async function ensureConfigDir2() {
476
- await mkdir2(CONFIG_DIR2, { recursive: true });
477
- }
478
- async function readConfig() {
479
- await ensureConfigDir2();
480
- try {
481
- await access2(CONFIG_FILE);
482
- const content = await readFile2(CONFIG_FILE, "utf-8");
483
- return ConfigSchema.parse(JSON.parse(content));
484
- } catch {
485
- return ConfigSchema.parse({});
486
- }
487
- }
488
- async function writeConfig(config2) {
489
- await ensureConfigDir2();
490
- await writeFile2(CONFIG_FILE, JSON.stringify(config2, null, 2), "utf-8");
491
- }
492
- var ConfigManager = class {
493
- configCache = null;
494
- async getConfig() {
495
- if (!this.configCache) {
496
- this.configCache = await readConfig();
497
- }
498
- return this.configCache;
499
- }
500
- async saveConfig(config2) {
501
- this.configCache = config2;
502
- await writeConfig(config2);
503
- }
504
- async getDefaults() {
505
- const config2 = await this.getConfig();
506
- return config2.defaults;
507
- }
508
- async setDefaults(defaults) {
509
- const config2 = await this.getConfig();
510
- config2.defaults = { ...config2.defaults, ...defaults };
511
- await this.saveConfig(config2);
512
- }
513
- async getActiveMcpId() {
514
- const config2 = await this.getConfig();
515
- return config2.activeMcpId;
516
- }
517
- async setActiveMcpId(id) {
518
- const config2 = await this.getConfig();
519
- config2.activeMcpId = id;
520
- await this.saveConfig(config2);
521
- }
522
- async clear() {
523
- const emptyConfig = ConfigSchema.parse({});
524
- await this.saveConfig(emptyConfig);
525
- }
526
- };
527
- var config = new ConfigManager();
528
-
529
- // src/commands/logout.ts
530
- var logoutCommand = new Command2("logout").description("Log out from WaniWani").action(async (_, command) => {
646
+ import { Command as Command3 } from "commander";
647
+ var logoutCommand = new Command3("logout").description("Log out from WaniWani").action(async (_, command) => {
531
648
  const globalOptions = command.optsWithGlobals();
532
649
  const json = globalOptions.json ?? false;
533
650
  try {
@@ -553,14 +670,13 @@ var logoutCommand = new Command2("logout").description("Log out from WaniWani").
553
670
  });
554
671
 
555
672
  // src/commands/mcp/index.ts
556
- import { Command as Command10 } from "commander";
673
+ import { Command as Command11 } from "commander";
557
674
 
558
675
  // src/commands/mcp/create.ts
559
- import { Command as Command3 } from "commander";
676
+ import { Command as Command4 } from "commander";
560
677
  import ora2 from "ora";
561
678
 
562
679
  // src/lib/api.ts
563
- var API_BASE_URL3 = process.env.WANIWANI_API_URL || "https://waniwani.com";
564
680
  var ApiError = class extends CLIError {
565
681
  constructor(message, code, statusCode, details) {
566
682
  super(message, code, details);
@@ -587,7 +703,8 @@ async function request(method, path, options) {
587
703
  }
588
704
  headers.Authorization = `Bearer ${token}`;
589
705
  }
590
- const url = `${API_BASE_URL3}${path}`;
706
+ const baseUrl = await config.getApiUrl();
707
+ const url = `${baseUrl}${path}`;
591
708
  const response = await fetch(url, {
592
709
  method,
593
710
  headers,
@@ -624,11 +741,11 @@ var api = {
624
741
  get: (path, options) => request("GET", path, options),
625
742
  post: (path, body, options) => request("POST", path, { body, ...options }),
626
743
  delete: (path, options) => request("DELETE", path, options),
627
- getBaseUrl: () => API_BASE_URL3
744
+ getBaseUrl: () => config.getApiUrl()
628
745
  };
629
746
 
630
747
  // src/commands/mcp/create.ts
631
- var createCommand = new Command3("create").description("Create a new MCP sandbox from template").argument("<name>", "Name for the MCP project").action(async (name, _, command) => {
748
+ 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) => {
632
749
  const globalOptions = command.optsWithGlobals();
633
750
  const json = globalOptions.json ?? false;
634
751
  try {
@@ -637,12 +754,24 @@ var createCommand = new Command3("create").description("Create a new MCP sandbox
637
754
  name
638
755
  });
639
756
  spinner.succeed("MCP sandbox created");
640
- config.setActiveMcpId(result.id);
757
+ const useProjectConfig = !options.global && hasProjectConfig();
758
+ if (useProjectConfig) {
759
+ await saveProjectConfig({ mcpId: result.id });
760
+ } else {
761
+ await config.setActiveMcpId(result.id);
762
+ }
641
763
  if (json) {
642
- formatOutput(result, true);
764
+ formatOutput(
765
+ { ...result, scope: useProjectConfig ? "project" : "global" },
766
+ true
767
+ );
643
768
  } else {
769
+ const scope = useProjectConfig ? "(saved to project)" : "(saved globally)";
644
770
  console.log();
645
- formatSuccess(`MCP sandbox "${name}" created successfully!`, false);
771
+ formatSuccess(
772
+ `MCP sandbox "${name}" created successfully! ${scope}`,
773
+ false
774
+ );
646
775
  console.log();
647
776
  console.log(` MCP ID: ${result.id}`);
648
777
  console.log(` Sandbox ID: ${result.sandboxId}`);
@@ -660,9 +789,9 @@ var createCommand = new Command3("create").description("Create a new MCP sandbox
660
789
  });
661
790
 
662
791
  // src/commands/mcp/deploy.ts
663
- import { Command as Command4 } from "commander";
792
+ import { Command as Command5 } from "commander";
664
793
  import ora3 from "ora";
665
- var deployCommand = new Command4("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) => {
794
+ var deployCommand = new Command5("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) => {
666
795
  const globalOptions = command.optsWithGlobals();
667
796
  const json = globalOptions.json ?? false;
668
797
  try {
@@ -708,9 +837,9 @@ var deployCommand = new Command4("deploy").description("Deploy MCP server to Git
708
837
 
709
838
  // src/commands/mcp/list.ts
710
839
  import chalk4 from "chalk";
711
- import { Command as Command5 } from "commander";
840
+ import { Command as Command6 } from "commander";
712
841
  import ora4 from "ora";
713
- var listCommand = new Command5("list").description("List all MCPs in your organization").option("--all", "Include stopped/expired MCPs").action(async (options, command) => {
842
+ var listCommand = new Command6("list").description("List all MCPs in your organization").option("--all", "Include stopped/expired MCPs").action(async (options, command) => {
714
843
  const globalOptions = command.optsWithGlobals();
715
844
  const json = globalOptions.json ?? false;
716
845
  try {
@@ -768,9 +897,9 @@ var listCommand = new Command5("list").description("List all MCPs in your organi
768
897
 
769
898
  // src/commands/mcp/status.ts
770
899
  import chalk5 from "chalk";
771
- import { Command as Command6 } from "commander";
900
+ import { Command as Command7 } from "commander";
772
901
  import ora5 from "ora";
773
- var statusCommand = new Command6("status").description("Show current MCP sandbox status").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
902
+ var statusCommand = new Command7("status").description("Show current MCP sandbox status").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
774
903
  const globalOptions = command.optsWithGlobals();
775
904
  const json = globalOptions.json ?? false;
776
905
  try {
@@ -810,9 +939,9 @@ var statusCommand = new Command6("status").description("Show current MCP sandbox
810
939
  });
811
940
 
812
941
  // src/commands/mcp/stop.ts
813
- import { Command as Command7 } from "commander";
942
+ import { Command as Command8 } from "commander";
814
943
  import ora6 from "ora";
815
- var stopCommand = new Command7("stop").description("Stop and clean up the MCP sandbox").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
944
+ var stopCommand = new Command8("stop").description("Stop and clean up the MCP sandbox").option("--mcp-id <id>", "Specific MCP ID").action(async (options, command) => {
816
945
  const globalOptions = command.optsWithGlobals();
817
946
  const json = globalOptions.json ?? false;
818
947
  try {
@@ -842,9 +971,9 @@ var stopCommand = new Command7("stop").description("Stop and clean up the MCP sa
842
971
 
843
972
  // src/commands/mcp/test.ts
844
973
  import chalk6 from "chalk";
845
- import { Command as Command8 } from "commander";
974
+ import { Command as Command9 } from "commander";
846
975
  import ora7 from "ora";
847
- var testCommand = new Command8("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(
976
+ var testCommand = new Command9("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(
848
977
  async (tool, args, options, command) => {
849
978
  const globalOptions = command.optsWithGlobals();
850
979
  const json = globalOptions.json ?? false;
@@ -932,9 +1061,9 @@ Test a tool: waniwani mcp test <tool-name> '{"arg": "value"}'`
932
1061
  );
933
1062
 
934
1063
  // src/commands/mcp/use.ts
935
- import { Command as Command9 } from "commander";
1064
+ import { Command as Command10 } from "commander";
936
1065
  import ora8 from "ora";
937
- var useCommand = new Command9("use").description("Select an MCP to use for subsequent commands").argument("<name>", "Name of the MCP to use").action(async (name, _, command) => {
1066
+ var useCommand = new Command10("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) => {
938
1067
  const globalOptions = command.optsWithGlobals();
939
1068
  const json = globalOptions.json ?? false;
940
1069
  try {
@@ -952,11 +1081,20 @@ var useCommand = new Command9("use").description("Select an MCP to use for subse
952
1081
  `MCP "${name}" is ${mcp.status}. Only active MCPs can be used.`
953
1082
  );
954
1083
  }
955
- await config.setActiveMcpId(mcp.id);
1084
+ const useProjectConfig = !options.global && hasProjectConfig();
1085
+ if (useProjectConfig) {
1086
+ await saveProjectConfig({ mcpId: mcp.id });
1087
+ } else {
1088
+ await config.setActiveMcpId(mcp.id);
1089
+ }
956
1090
  if (json) {
957
- formatOutput({ selected: mcp }, true);
1091
+ formatOutput(
1092
+ { selected: mcp, scope: useProjectConfig ? "project" : "global" },
1093
+ true
1094
+ );
958
1095
  } else {
959
- formatSuccess(`Now using MCP "${name}"`, false);
1096
+ const scope = useProjectConfig ? "(project)" : "(global)";
1097
+ formatSuccess(`Now using MCP "${name}" ${scope}`, false);
960
1098
  console.log();
961
1099
  console.log(` MCP ID: ${mcp.id}`);
962
1100
  console.log(` Preview URL: ${mcp.previewUrl}`);
@@ -973,16 +1111,16 @@ var useCommand = new Command9("use").description("Select an MCP to use for subse
973
1111
  });
974
1112
 
975
1113
  // src/commands/mcp/index.ts
976
- var mcpCommand = new Command10("mcp").description("MCP sandbox management commands").addCommand(createCommand).addCommand(listCommand).addCommand(useCommand).addCommand(statusCommand).addCommand(stopCommand).addCommand(testCommand).addCommand(deployCommand);
1114
+ var mcpCommand = new Command11("mcp").description("MCP sandbox management commands").addCommand(createCommand).addCommand(listCommand).addCommand(useCommand).addCommand(statusCommand).addCommand(stopCommand).addCommand(testCommand).addCommand(deployCommand);
977
1115
 
978
1116
  // src/commands/org/index.ts
979
- import { Command as Command13 } from "commander";
1117
+ import { Command as Command14 } from "commander";
980
1118
 
981
1119
  // src/commands/org/list.ts
982
1120
  import chalk7 from "chalk";
983
- import { Command as Command11 } from "commander";
1121
+ import { Command as Command12 } from "commander";
984
1122
  import ora9 from "ora";
985
- var listCommand2 = new Command11("list").description("List your organizations").action(async (_, command) => {
1123
+ var listCommand2 = new Command12("list").description("List your organizations").action(async (_, command) => {
986
1124
  const globalOptions = command.optsWithGlobals();
987
1125
  const json = globalOptions.json ?? false;
988
1126
  try {
@@ -1032,9 +1170,9 @@ var listCommand2 = new Command11("list").description("List your organizations").
1032
1170
  });
1033
1171
 
1034
1172
  // src/commands/org/switch.ts
1035
- import { Command as Command12 } from "commander";
1173
+ import { Command as Command13 } from "commander";
1036
1174
  import ora10 from "ora";
1037
- var switchCommand = new Command12("switch").description("Switch to a different organization").argument("<name>", "Name or slug of the organization to switch to").action(async (name, _, command) => {
1175
+ var switchCommand = new Command13("switch").description("Switch to a different organization").argument("<name>", "Name or slug of the organization to switch to").action(async (name, _, command) => {
1038
1176
  const globalOptions = command.optsWithGlobals();
1039
1177
  const json = globalOptions.json ?? false;
1040
1178
  try {
@@ -1071,22 +1209,22 @@ var switchCommand = new Command12("switch").description("Switch to a different o
1071
1209
  });
1072
1210
 
1073
1211
  // src/commands/org/index.ts
1074
- var orgCommand = new Command13("org").description("Organization management commands").addCommand(listCommand2).addCommand(switchCommand);
1212
+ var orgCommand = new Command14("org").description("Organization management commands").addCommand(listCommand2).addCommand(switchCommand);
1075
1213
 
1076
1214
  // src/commands/task.ts
1077
1215
  import chalk8 from "chalk";
1078
- import { Command as Command14 } from "commander";
1216
+ import { Command as Command15 } from "commander";
1079
1217
  import ora11 from "ora";
1080
- var taskCommand = new Command14("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", "claude-sonnet-4-20250514").option("--max-steps <n>", "Maximum tool use steps", "10").action(async (prompt, options, command) => {
1218
+ var taskCommand = new Command15("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) => {
1081
1219
  const globalOptions = command.optsWithGlobals();
1082
1220
  const json = globalOptions.json ?? false;
1083
1221
  try {
1084
1222
  let mcpId = options.mcpId;
1085
1223
  if (!mcpId) {
1086
- mcpId = await config.getActiveMcpId();
1224
+ mcpId = await config.getEffectiveMcpId();
1087
1225
  if (!mcpId) {
1088
1226
  throw new McpError(
1089
- "No active MCP. Run 'waniwani mcp create <name>' or 'waniwani mcp use <name>'."
1227
+ "No active MCP. Run 'waniwani init' then 'waniwani mcp use <name>'."
1090
1228
  );
1091
1229
  }
1092
1230
  }
@@ -1096,7 +1234,9 @@ var taskCommand = new Command14("task").description("Send a task to Claude runni
1096
1234
  "Not logged in. Run 'waniwani login' to authenticate."
1097
1235
  );
1098
1236
  }
1099
- const maxSteps = parseInt(options.maxSteps, 10);
1237
+ const defaults = await config.getEffectiveDefaults();
1238
+ const model = options.model ?? defaults.model;
1239
+ const maxSteps = options.maxSteps ? Number.parseInt(options.maxSteps, 10) : defaults.maxSteps;
1100
1240
  if (!json) {
1101
1241
  console.log();
1102
1242
  console.log(chalk8.bold("Task:"), prompt);
@@ -1113,7 +1253,7 @@ var taskCommand = new Command14("task").description("Send a task to Claude runni
1113
1253
  },
1114
1254
  body: JSON.stringify({
1115
1255
  prompt,
1116
- model: options.model,
1256
+ model,
1117
1257
  maxSteps
1118
1258
  })
1119
1259
  });
@@ -1222,9 +1362,10 @@ var taskCommand = new Command14("task").description("Send a task to Claude runni
1222
1362
 
1223
1363
  // src/cli.ts
1224
1364
  var version = "0.1.0";
1225
- var program = new Command15().name("waniwani").description("WaniWani CLI for MCP development workflow").version(version).option("--json", "Output results as JSON").option("--verbose", "Enable verbose logging");
1365
+ var program = new Command16().name("waniwani").description("WaniWani CLI for MCP development workflow").version(version).option("--json", "Output results as JSON").option("--verbose", "Enable verbose logging");
1226
1366
  program.addCommand(loginCommand);
1227
1367
  program.addCommand(logoutCommand);
1368
+ program.addCommand(initCommand);
1228
1369
  program.addCommand(mcpCommand);
1229
1370
  program.addCommand(taskCommand);
1230
1371
  program.addCommand(orgCommand);